diff --git a/flow b/flow index 1c1371b..cf59b41 100755 Binary files a/flow and b/flow differ diff --git a/grammar.txt b/grammar.txt index 1596ad1..8a92464 100644 --- a/grammar.txt +++ b/grammar.txt @@ -14,10 +14,10 @@ additive_expression: | additive_expression '-' multiplicative_expression ; -multiplicative_expression: - number - | number '*' multiplicative_expression - | number '/' multiplicative_expression +multiplicative_expression: prefix_expression + | multiplicative_expression '*' prefix_expression + | multiplicative_expression '/' prefix_expression + | multiplicative_expression '%' prefix_expression ; number: INTLIT_T @@ -99,17 +99,28 @@ function_call : identifier '(' expression ')' return_statement: 'return' '(' expression ')' ; -prefix_expression: primary - | '*' prefix_expression - | '%' prefix_expression +prefix_expression: postfix_expression + | '++' prefix_expression + | '--' prefix_expression + | prefix_operator prefix_expression ; -primary_expression: IDENTIFIER - | CONSTANT - | STRING_LITERAL +primary_expression: T_IDENT + | T_INTLIT + | T_STRLIT | '(' expression ')' ; postfix_expression : primary_expression | postfix_expression '[' expression ']' + | postfix_expression '(' expression ')' + | postfix_expression '++' + | postfix_expression '--' + ; +prefix_operator: '&' + | '*' + | '-' + | '~' + | '!' + ; diff --git a/src/cg.c b/src/cg.c index ecef560..51e9028 100644 --- a/src/cg.c +++ b/src/cg.c @@ -76,26 +76,52 @@ int cgloadint(int value, int type) { } // Load a value from a variable into a register. -// Return the number of the register -int cgloadglob(int id) { +// Return the number of the register. If the +// operation is pre- or post-increment/decrement, +// also perform this action. +int cgloadglob(int id, int op) { // Get a new register int r = alloc_register(); // Print out the code to initialise it switch (Gsym[id].type) { case P_CHAR: + if (op == A_PREINC) + fprintf(Outfile, "\tincb\t%s(\%%rip)\n", Gsym[id].name); + if (op == A_PREDEC) + fprintf(Outfile, "\tdecb\t%s(\%%rip)\n", Gsym[id].name); fprintf(Outfile, "\tmovzbq\t%s(%%rip), %s\n", Gsym[id].name, reglist[r]); + if (op == A_POSTINC) + fprintf(Outfile, "\tincb\t%s(\%%rip)\n", Gsym[id].name); + if (op == A_POSTDEC) + fprintf(Outfile, "\tdecb\t%s(\%%rip)\n", Gsym[id].name); break; case P_INT: - fprintf(Outfile, "\tmovzbl\t%s(\%%rip), %s\n", Gsym[id].name, + if (op == A_PREINC) + fprintf(Outfile, "\tincl\t%s(\%%rip)\n", Gsym[id].name); + if (op == A_PREDEC) + fprintf(Outfile, "\tdecl\t%s(\%%rip)\n", Gsym[id].name); + fprintf(Outfile, "\tmovslq\t%s(\%%rip), %s\n", Gsym[id].name, reglist[r]); + if (op == A_POSTINC) + fprintf(Outfile, "\tincl\t%s(\%%rip)\n", Gsym[id].name); + if (op == A_POSTDEC) + fprintf(Outfile, "\tdecl\t%s(\%%rip)\n", Gsym[id].name); break; case P_LONG: case P_CHARPTR: case P_INTPTR: case P_LONGPTR: + if (op == A_PREINC) + fprintf(Outfile, "\tincq\t%s(\%%rip)\n", Gsym[id].name); + if (op == A_PREDEC) + fprintf(Outfile, "\tdecq\t%s(\%%rip)\n", Gsym[id].name); fprintf(Outfile, "\tmovq\t%s(\%%rip), %s\n", Gsym[id].name, reglist[r]); + if (op == A_POSTINC) + fprintf(Outfile, "\tincq\t%s(\%%rip)\n", Gsym[id].name); + if (op == A_POSTDEC) + fprintf(Outfile, "\tdecq\t%s(\%%rip)\n", Gsym[id].name); break; default: fatald("Bad type in cgloadglob:", Gsym[id].type); @@ -103,7 +129,6 @@ int cgloadglob(int id) { return (r); } - // Given the label number of a global string, // load its address into a new register int cgloadglobstr(int id) { @@ -113,7 +138,6 @@ int cgloadglobstr(int id) { return (r); } - // Add two registers together and return // the number of the register with the result int cgadd(int r1, int r2) { @@ -149,6 +173,71 @@ int cgdiv(int r1, int r2) { return (r1); } +int cgand(int r1, int r2) { + fprintf(Outfile, "\tandq\t%s, %s\n", reglist[r1], reglist[r2]); + free_register(r1); + return (r2); +} + +int cgor(int r1, int r2) { + fprintf(Outfile, "\torq\t%s, %s\n", reglist[r1], reglist[r2]); + free_register(r1); + return (r2); +} + +int cgxor(int r1, int r2) { + fprintf(Outfile, "\txorq\t%s, %s\n", reglist[r1], reglist[r2]); + free_register(r1); + return (r2); +} + +int cgshl(int r1, int r2) { + fprintf(Outfile, "\tmovb\t%s, %%cl\n", breglist[r2]); + fprintf(Outfile, "\tshlq\t%%cl, %s\n", reglist[r1]); + free_register(r2); + return (r1); +} + +int cgshr(int r1, int r2) { + fprintf(Outfile, "\tmovb\t%s, %%cl\n", breglist[r2]); + fprintf(Outfile, "\tshrq\t%%cl, %s\n", reglist[r1]); + free_register(r2); + return (r1); +} + +// Negate a register's value +int cgnegate(int r) { + fprintf(Outfile, "\tnegq\t%s\n", reglist[r]); + return (r); +} + +// Invert a register's value +int cginvert(int r) { + fprintf(Outfile, "\tnotq\t%s\n", reglist[r]); + return (r); +} + +// Logically negate a register's value +int cglognot(int r) { + fprintf(Outfile, "\ttest\t%s, %s\n", reglist[r], reglist[r]); + fprintf(Outfile, "\tsete\t%s\n", breglist[r]); + fprintf(Outfile, "\tmovzbq\t%s, %s\n", breglist[r], reglist[r]); + return (r); +} + +// Convert an integer value to a boolean value. Jump if +// it's an IF or WHILE operation +int cgboolean(int r, int op, int label) { + fprintf(Outfile, "\ttest\t%s, %s\n", reglist[r], reglist[r]); + if (op == A_IF || op == A_WHILE) + fprintf(Outfile, "\tje\tL%d\n", label); + else { + fprintf(Outfile, "\tsetnz\t%s\n", breglist[r]); + fprintf(Outfile, "\tmovzbq\t%s, %s\n", breglist[r], reglist[r]); + } + return (r); +} + // Call a function with one argument from the given register // Return the register with the result int cgcall(int r, int id) { @@ -164,7 +253,7 @@ int cgcall(int r, int id) { // Shift a register left by a constant int cgshlconst(int r, int val) { fprintf(Outfile, "\tsalq\t$%d, %s\n", val, reglist[r]); - return(r); + return (r); } // Store a register's value into a variable @@ -214,28 +303,33 @@ void cgglobsym(int id) { fprintf(Outfile, "%s:", Gsym[id].name); // Generate the space - for (int i=0; i < Gsym[id].size; i++) { - switch(typesize) { - case 1: fprintf(Outfile, "\t.byte\t0\n"); break; - case 4: fprintf(Outfile, "\t.long\t0\n"); break; - case 8: fprintf(Outfile, "\t.quad\t0\n"); break; - default: fatald("Unknown typesize in cgglobsym: ", typesize); + for (int i = 0; i < Gsym[id].size; i++) { + switch (typesize) { + case 1: + fprintf(Outfile, "\t.byte\t0\n"); + break; + case 4: + fprintf(Outfile, "\t.long\t0\n"); + break; + case 8: + fprintf(Outfile, "\t.quad\t0\n"); + break; + default: + fatald("Unknown typesize in cgglobsym: ", typesize); } } } - // Generate a global string and its start label void cgglobstr(int l, char *strvalue) { char *cptr; cglabel(l); - for (cptr= strvalue; *cptr; cptr++) { + for (cptr = strvalue; *cptr; cptr++) { fprintf(Outfile, "\t.byte\t%d\n", *cptr); } fprintf(Outfile, "\t.byte\t0\n"); } - // List of comparison instructions, // in AST order: A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE static char *cmplist[] = @@ -327,7 +421,7 @@ int cgderef(int r, int type) { fprintf(Outfile, "\tmovzbq\t(%s), %s\n", reglist[r], reglist[r]); break; case P_INTPTR: - fprintf(Outfile, "\tmovq\t(%s), %s\n", reglist[r], reglist[r]); + fprintf(Outfile, "\tmovslq\t(%s), %s\n", reglist[r], reglist[r]); break; case P_LONGPTR: fprintf(Outfile, "\tmovq\t(%s), %s\n", reglist[r], reglist[r]); diff --git a/src/expr.c b/src/expr.c index aa15cdc..4abb849 100644 --- a/src/expr.c +++ b/src/expr.c @@ -72,6 +72,52 @@ static AST_T *array_access(void) } +// Parse a postfix expression and return +// an AST node representing it. The +// identifier is already in Text. +static AST_T *postfix(void) +{ + AST_T *n; + int id; + + // Scan in the next token to see if we have postfix expression + scan(&Token); + + // Function call + if (Token.token == T_LPAREN) + return (funccall()); + + // An array reference + if (Token.token == T_LBRACKET) + return (array_access()); + + // A variable. Check that the variable exists. + id = findglob(Text); + if (id == -1 || Gsym[id].stype != S_VARIABLE) + fatals("Unknown variable", Text); + + switch (Token.token) + { + // Post-increment: skip over the token + case T_INC: + scan(&Token); + n = mkastleaf(A_POSTINC, Gsym[id].type, id); + break; + + // Post-decrement: skip over the token + case T_DEC: + scan(&Token); + n = mkastleaf(A_POSTDEC, Gsym[id].type, id); + break; + + // Just a variable reference + default: n = mkastleaf(A_IDENT, Gsym[id].type, id); + } + return (n); +} + + + // Parse a primary factor and return an // AST node representing it. static AST_T *primary(void) { @@ -96,29 +142,7 @@ static AST_T *primary(void) { break; case T_IDENT: - // This could be a variable or a function call. - // Scan in the next token to find out - scan(&Token); - - // It's a '(', so a function call - if (Token.token == T_LPAREN) - return (funccall()); - - // It's a '[', so an array reference - if (Token.token == T_LBRACKET) - return (array_access()); - - // Not a function call, so reject the new token - reject_token(&Token); - - // Check that the variable exists. XXX Add structural type test - id = findglob(Text); - if (id == -1 || Gsym[id].stype != S_VARIABLE) - fatals("Unknown variable", Text); - - // Make a leaf AST node for it - n = mkastleaf(A_IDENT, Gsym[id].type, id); - break; + return (postfix()); case T_LPAREN: // Beginning of a parenthesised expression, skip the '('. @@ -141,7 +165,7 @@ static AST_T *primary(void) { // Convert a binary operator token into a binary AST operation. // We rely on a 1:1 mapping from token to AST operation static int binastop(int tokentype) { - if (tokentype > T_EOF && tokentype < T_INTLIT) + if (tokentype > T_EOF && tokentype <= T_SLASH) return (tokentype); fatald("Syntax error, token", tokentype); return (0); // Keep -Wall happy @@ -158,18 +182,20 @@ static int rightassoc(int tokentype) { // Operator precedence for each token. Must // match up with the order of tokens in defs.h static int OpPrec[] = { - 0, 10, // T_EOF, T_ASSIGN - 20, 20, // T_PLUS, T_MINUS - 30, 30, // T_STAR, T_SLASH - 40, 40, // T_EQ, T_NE - 50, 50, 50, 50 // T_LT, T_GT, T_LE, T_GE + 0, 10, 20, 30, // T_EOF, T_ASSIGN, T_LOGOR, T_LOGAND, + 40, 50, 60, // T_OR, T_XOR, T_AMPER, + 70, 70, // T_EQ, T_NE, + 80, 80, 80, 80, // T_LT, T_GT, T_LE, T_GE, + 90, 90, // T_LSHIFT, T_RSHIFT, + 100, 100, // T_PLUS, T_MINUS + 110, 110, // T_STAR, T_SLASH }; // Check that we have a binary operator and // return its precedence. static int op_precedence(int tokentype) { int prec; - if (tokentype >= T_VOID) + if (tokentype > T_SLASH) fatald("Token with no precedence in op_precedence:", tokentype); prec = OpPrec[tokentype]; if (prec == 0) @@ -212,6 +238,73 @@ AST_T *prefix(void) { // Prepend an A_DEREF operation to the tree tree = mkastunary(A_DEREF, value_at(tree->type), tree, 0); break; + + case T_MINUS: + // Get the next token and parse it + // recursively as a prefix expression + scan(&Token); + tree = prefix(); + + // Prepend a A_NEGATE operation to the tree and + // make the child an rvalue. Because chars are unsigned, + // also widen this to int so that it's signed + tree->rvalue = 1; + tree = modify_type(tree, P_INT, 0); + tree = mkastunary(A_NEGATE, tree->type, tree, 0); + break; + + case T_INVERT: + // Get the next token and parse it + // recursively as a prefix expression + scan(&Token); + tree = prefix(); + + // Prepend a A_INVERT operation to the tree and + // make the child an rvalue. + tree->rvalue = 1; + tree = mkastunary(A_INVERT, tree->type, tree, 0); + break; + + case T_LOGNOT: + // Get the next token and parse it + // recursively as a prefix expression + scan(&Token); + tree = prefix(); + + // Prepend a A_LOGNOT operation to the tree and + // make the child an rvalue. + tree->rvalue = 1; + tree = mkastunary(A_LOGNOT, tree->type, tree, 0); + break; + + case T_INC: + // Get the next token and parse it + // recursively as a prefix expression + scan(&Token); + tree = prefix(); + + // For now, ensure it's an identifier + if (tree->op != A_IDENT) + fatal("++ operator must be followed by an identifier"); + + // Prepend an A_PREINC operation to the tree + tree = mkastunary(A_PREINC, tree->type, tree, 0); + break; + + case T_DEC: + // Get the next token and parse it + // recursively as a prefix expression + scan(&Token); + tree = prefix(); + + // For now, ensure it's an identifier + if (tree->op != A_IDENT) + fatal("-- operator must be followed by an identifier"); + + // Prepend an A_PREDEC operation to the tree + tree = mkastunary(A_PREDEC, tree->type, tree, 0); + break; + default: tree = primary(); } diff --git a/src/gen.c b/src/gen.c index 45dcc2a..c2dfe82 100644 --- a/src/gen.c +++ b/src/gen.c @@ -117,10 +117,17 @@ int genAST(AST_T *n, int label, int parentASTop) { rightreg = genAST(n->right, NOLABEL, n->op); switch (n->op) { - case A_ADD: return (cgadd(leftreg, rightreg)); + case A_ADD: return (cgadd(leftreg, rightreg)); case A_SUBTRACT: return (cgsub(leftreg, rightreg)); case A_MULTIPLY: return (cgmul(leftreg, rightreg)); - case A_DIVIDE: return (cgdiv(leftreg, rightreg)); + case A_DIVIDE: return (cgdiv(leftreg, rightreg)); + + case A_AND: return (cgand(leftreg, rightreg)); + case A_OR: return (cgor(leftreg, rightreg)); + case A_XOR: return (cgxor(leftreg, rightreg)); + case A_LSHIFT: return (cgshl(leftreg, rightreg)); + case A_RSHIFT: return (cgshr(leftreg, rightreg)); + case A_EQ: case A_NE: case A_LT: @@ -131,9 +138,9 @@ int genAST(AST_T *n, int label, int parentASTop) { // a compare followed by a jump. Otherwise, compare registers // and set one to 1 or 0 based on the comparison. if (parentASTop == A_IF || parentASTop == A_WHILE) - return (cgcompare_and_jump(n->op, leftreg, rightreg, label)); + return (cgcompare_and_jump(n->op, leftreg, rightreg, label)); else - return (cgcompare_and_set(n->op, leftreg, rightreg)); + return (cgcompare_and_set(n->op, leftreg, rightreg)); case A_INTLIT: return (cgloadint(n->v.intvalue, n->type)); case A_STRLIT: @@ -142,14 +149,14 @@ int genAST(AST_T *n, int label, int parentASTop) { // Load our value if we are an rvalue // or we are being dereferenced if (n->rvalue || parentASTop== A_DEREF) - return (cgloadglob(n->v.id)); + return (cgloadglob(n->v.id, n->op)); else return (NOREG); case A_ASSIGN: // Are we assigning to an identifier or through a pointer? switch (n->right->op) { case A_IDENT: return (cgstorglob(leftreg, n->right->v.id)); - case A_DEREF: return (cgstorderef(leftreg, rightreg, n->right->type)); + case A_DEREF: return (cgstorderef(leftreg, rightreg, n->right->type)); default: fatald("Can't A_ASSIGN in genAST(), op", n->op); } case A_WIDEN: @@ -182,6 +189,31 @@ int genAST(AST_T *n, int label, int parentASTop) { rightreg= cgloadint(n->v.size, P_INT); return (cgmul(leftreg, rightreg)); } + case A_POSTINC: + // Load the variable's value into a register, + // then increment it + return (cgloadglob(n->v.id, n->op)); + case A_POSTDEC: + // Load the variable's value into a register, + // then decrement it + return (cgloadglob(n->v.id, n->op)); + case A_PREINC: + // Load and increment the variable's value into a register + return (cgloadglob(n->left->v.id, n->op)); + case A_PREDEC: + // Load and decrement the variable's value into a register + return (cgloadglob(n->left->v.id, n->op)); + case A_NEGATE: + return (cgnegate(leftreg)); + case A_INVERT: + return (cginvert(leftreg)); + case A_LOGNOT: + return (cglognot(leftreg)); + case A_TOBOOL: + // If the parent AST node is an A_IF or A_WHILE, generate + // a compare followed by a jump. Otherwise, set the register + // to 0 or 1 based on it's zeroeness or non-zeroeness + return (cgboolean(leftreg, parentASTop, label)); default: fatald("Unknown AST operator", n->op); } diff --git a/src/include/decl.h b/src/include/decl.h index 0ed57cb..ff7344d 100644 --- a/src/include/decl.h +++ b/src/include/decl.h @@ -33,7 +33,7 @@ void cgpostamble(); void cgfuncpreamble(int id); void cgfuncpostamble(int id); int cgloadint(int value, int type); -int cgloadglob(int id); +int cgloadglob(int id, int op); int cgloadglobstr(int id); int cgadd(int r1, int r2); int cgsub(int r1, int r2); @@ -54,6 +54,15 @@ void cgreturn(int reg, int id); int cgaddress(int id); int cgderef(int r, int type); int cgstorderef(int r1, int r2, int type); +int cgnegate(int r); +int cginvert(int r); +int cglognot(int r); +int cgboolean(int r, int op, int label); +int cgand(int r1, int r2); +int cgor(int r1, int r2); +int cgxor(int r1, int r2); +int cgshl(int r1, int r2); +int cgshr(int r1, int r2); // expr.c AST_T *binexpr(int ptp); diff --git a/src/include/defs.h b/src/include/defs.h index 1d6d26a..a9e8bd4 100644 --- a/src/include/defs.h +++ b/src/include/defs.h @@ -11,20 +11,28 @@ // Token types enum { T_EOF, - // Operators - T_ASSIGN, - T_PLUS, T_MINUS, - T_STAR, T_SLASH, - T_EQ, T_NE, - T_LT, T_GT, T_LE, T_GE, + + // Binary Operators + T_ASSIGN, T_LOGOR, T_LOGAND, // '=', 'or', 'and', + T_OR, T_XOR, T_AMPER, // '|', '^', '&', + T_EQ, T_NE, // '==', '!=', + T_LT, T_GT, T_LE, T_GE, // '<', '>', '<=', '>=', + T_LSHIFT, T_RSHIFT, // '<<', '>>', + T_PLUS, T_MINUS, T_STAR, T_SLASH, // '+', '-', '*', '/', + + // Other operators + T_INC, T_DEC, T_INVERT, T_LOGNOT, // '++', '--', '~', 'not', + // Type keywords - T_VOID, T_CHAR, T_INT, T_LONG, + T_VOID, T_CHAR, T_INT, T_LONG, // 'void', 'char', 'int', 'long', + + // Other keywords + T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN, // 'if', 'else', 'while', 'for', 'return', + // Structural tokens T_INTLIT, T_STRLIT, T_SEMI, T_IDENT, - T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN, - T_LBRACKET, T_RBRACKET, T_AMPER, T_LOGAND, - // Other keywords - T_IF, T_ELSE, T_WHILE, T_FOR, T_RETURN + T_LBRACE, T_RBRACE, T_LPAREN, T_RPAREN, // '{', '}', '(', ')', + T_LBRACKET, T_RBRACKET // '[', ']' }; // Token structure @@ -36,11 +44,14 @@ typedef struct token { // AST node types. The first few line up // with the related tokens enum { - A_ASSIGN= 1, A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, - A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, + A_ASSIGN= 1, A_LOGOR, A_LOGAND, A_OR, A_XOR, A_AND, + A_EQ, A_NE, A_LT, A_GT, A_LE, A_GE, A_LSHIFT, A_RSHIFT, + A_ADD, A_SUBTRACT, A_MULTIPLY, A_DIVIDE, A_INTLIT, A_STRLIT, A_IDENT, A_GLUE, A_IF, A_WHILE, A_FUNCTION, A_WIDEN, A_RETURN, - A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE + A_FUNCCALL, A_DEREF, A_ADDR, A_SCALE, + A_PREINC, A_PREDEC, A_POSTINC, A_POSTDEC, + A_NEGATE, A_INVERT, A_LOGNOT, A_TOBOOL }; // Primitive types diff --git a/src/scan.c b/src/scan.c index a747576..7fbe925 100644 --- a/src/scan.c +++ b/src/scan.c @@ -153,39 +153,51 @@ static int scanident(int c, char *buf, int lim) { // to waste time strcmp()ing against all the keywords. static int keyword(char *s) { switch (*s) { + case 'a': + if (!strcmp(s, "and")) + return (T_LOGAND); + break; case 'c': if (!strcmp(s, "char")) - return (T_CHAR); + return (T_CHAR); break; case 'e': if (!strcmp(s, "else")) - return (T_ELSE); + return (T_ELSE); break; case 'f': if (!strcmp(s, "for")) - return (T_FOR); + return (T_FOR); break; case 'i': if (!strcmp(s, "if")) - return (T_IF); + return (T_IF); if (!strcmp(s, "int")) - return (T_INT); + return (T_INT); break; case 'l': if (!strcmp(s, "long")) - return (T_LONG); + return (T_LONG); + break; + case 'n': + if (!strcmp(s, "not")) + return (T_LOGNOT); + break; + case 'o': + if (!strcmp(s, "or")) + return (T_LOGOR); break; case 'r': if (!strcmp(s, "return")) - return (T_RETURN); + return (T_RETURN); break; case 'w': if (!strcmp(s, "while")) - return (T_WHILE); + return (T_WHILE); break; case 'v': if (!strcmp(s, "void")) - return (T_VOID); + return (T_VOID); break; } return (0); @@ -219,8 +231,8 @@ int scan(token_T *t) { // the input character switch (c) { case EOF: t->token = T_EOF; return (0); - case '+': t->token = T_PLUS; break; - case '-': t->token = T_MINUS; break; + case '+': if ((c = next()) == '+') { t->token = T_INC; } else { putback(c); t->token = T_PLUS; } break; + case '-': if ((c = next()) == '-') {t->token = T_DEC; } else { putback(c); t->token = T_MINUS; } break; case '*': t->token = T_STAR; break; case '/': t->token = T_SLASH; break; case ';': t->token = T_SEMI; break; @@ -230,11 +242,31 @@ int scan(token_T *t) { case ')': t->token = T_RPAREN; break; case '[': t->token = T_LBRACKET; break; case ']': t->token = T_RBRACKET; break; + case '~': t->token = T_INVERT; break; + case '&': t->token = T_AMPER; break; + case '^': t->token = T_XOR; break; + case '|': t->token = T_OR; break; case '=': if ((c = next()) == '=') { t->token = T_EQ; } else { putback(c); t->token = T_ASSIGN; } break; case '!': if ((c = next()) == '=') { t->token = T_NE; } else { fatalc("Unrecognised character", c); } break; - case '<': if ((c = next()) == '=') { t->token = T_LE; } else { putback(c); t->token = T_LT; } break; - case '>': if ((c = next()) == '=') { t->token = T_GE; } else { putback(c); t->token = T_GT; } break; - case '&': if ((c = next()) == '&') { t->token = T_LOGAND; } else { putback(c); t->token = T_AMPER; } break; + case '<': + if ((c = next()) == '=') { + t->token = T_LE; + } else if (c == '<') { + t->token = T_LSHIFT; + } else { + putback(c); t->token = T_LT; + } + break; + case '>': + if ((c = next()) == '=') { + t->token = T_GE; + } else if (c == '>') { + t->token = T_RSHIFT; + } else { + putback(c); + t->token = T_GT; + } + break; case '\'': // If it's a quote, scan in the // literal character value and diff --git a/src/stmt.c b/src/stmt.c index d372f4c..53cd5a7 100644 --- a/src/stmt.c +++ b/src/stmt.c @@ -23,7 +23,7 @@ static AST_T *if_statement(void) { // the tree's operation is a comparison. condAST = binexpr(0); if (condAST->op < A_EQ || condAST->op > A_GE) - fatal("Bad comparison operator"); + condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0); rparen(); // Get the AST for the compound statement @@ -53,7 +53,7 @@ static AST_T *while_statement(void) { // the tree's operation is a comparison. condAST = binexpr(0); if (condAST->op < A_EQ || condAST->op > A_GE) - fatal("Bad comparison operator"); + condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0); rparen(); // Get the AST for the compound statement @@ -81,7 +81,7 @@ static AST_T *for_statement(void) { // Get the condition and the ';' condAST = binexpr(0); if (condAST->op < A_EQ || condAST->op > A_GE) - fatal("Bad comparison operator"); + condAST = mkastunary(A_TOBOOL, condAST->type, condAST, 0); semi(); // Get the post_op statement and the ')' @@ -185,9 +185,9 @@ AST_T *compound_statement(void) { // new tree together if (tree != NULL) { if (left == NULL) - left = tree; + left = tree; else - left = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0); + left = mkastnode(A_GLUE, P_NONE, left, NULL, tree, 0); } // When we hit a right curly bracket, diff --git a/tests/input22.flow b/tests/input22.flow new file mode 100644 index 0000000..e7e3f34 --- /dev/null +++ b/tests/input22.flow @@ -0,0 +1,26 @@ +char a; char b; char c; +int d; int e; int f; +long g; long h; long i; + + +int main() { + b = 5; + c= 7; + a = b + c++; printint(a); + e = 5; + f = 7; + d = e + f++; printint(d); + h = 5; + i = 7; + g = h + i++; printint(g); + a = b-- + c; printint(a); + d = e-- + f; printint(d); + g = h-- + i; printint(g); + a = ++b + c; printint(a); + d = ++e + f; printint(d); + g = ++h + i; printint(g); + a = b * --c; printint(a); + d = e * --f; printint(d); + g = h * --i; printint(g); + return(0); +} diff --git a/tests/input23.flow b/tests/input23.flow new file mode 100644 index 0000000..31bd394 --- /dev/null +++ b/tests/input23.flow @@ -0,0 +1,28 @@ +char *str; +int x; + +int main() { + x = -23; + printint(x); + printint(-10 * -10); + + x = 1; + x = ~x; + printint(x); + + x = 2 > 5; + printint(x); + x = not x; + printint(x); + x = not x; + printint(x); + + x = 13; if (x) { printint(13); } + x = 0; if (not x) { printint(14); } + + for (str= "Hello world\n"; *str; str++) { + printchar(*str); + } + + return(0); +} diff --git a/tests/input24.flow b/tests/input24.flow new file mode 100644 index 0000000..e8b4b69 --- /dev/null +++ b/tests/input24.flow @@ -0,0 +1,16 @@ +int a; +int b; +int c; + +int main() { + a = 42; + b= 19; + + printint(a & b); + printint(a | b); + printint(a ^ b); + printint(1 << 3); + printint(63 >> 3); + return(0); +} + diff --git a/tests/results/out.input22.flow b/tests/results/out.input22.flow new file mode 100644 index 0000000..6086532 --- /dev/null +++ b/tests/results/out.input22.flow @@ -0,0 +1,12 @@ +12 +12 +12 +13 +13 +13 +13 +13 +13 +35 +35 +35 diff --git a/tests/results/out.input23.flow b/tests/results/out.input23.flow new file mode 100644 index 0000000..90ae7ff --- /dev/null +++ b/tests/results/out.input23.flow @@ -0,0 +1,9 @@ +-23 +100 +-2 +0 +1 +0 +13 +14 +Hello world diff --git a/tests/results/out.input24.flow b/tests/results/out.input24.flow new file mode 100644 index 0000000..993b6df --- /dev/null +++ b/tests/results/out.input24.flow @@ -0,0 +1,5 @@ +2 +59 +57 +8 +7