From c9b8ffc3897952deef9e23949ce42fdc09f14a24 Mon Sep 17 00:00:00 2001 From: Jack Palevich Date: Mon, 3 Aug 2009 14:42:57 -0700 Subject: [PATCH] Add support for "short" data type. --- libacc/FEATURES | 62 +++++++++++++++++++++++------------- libacc/acc.cpp | 62 ++++++++++++++++++++++++++++++++---- libacc/tests/data/short.c | 6 ++++ libacc/tests/runtimeTest.cpp | 8 +++++ libacc/tests/test.py | 5 +++ 5 files changed, 115 insertions(+), 28 deletions(-) create mode 100644 libacc/tests/data/short.c diff --git a/libacc/FEATURES b/libacc/FEATURES index 1a444150f..97a876d9e 100644 --- a/libacc/FEATURES +++ b/libacc/FEATURES @@ -1,6 +1,5 @@ -Supported C language subset (read joint example 'otccex.c' to have - an introduction to OTCC dialect): +Supported C language subset: - Expressions: @@ -13,35 +12,51 @@ Supported C language subset (read joint example 'otccex.c' to have * Parenthesis are supported. + * Comma operator is supported. + + * Trinary operator (?:) is not supported. + * Unary operators: '&', '*' (pointer indirection), '-' - (negation), '+', '!', '~', post fixed '++' and '--'. + (negation), '+', '!', '~', '++' and '--'. - * Pointer indirection ('*') only works with explicit cast to - 'char *', 'int *' or 'int (*)()' (function pointer). + * Pointer indirection ('*') is supported. - * '++', '--', and unary '&' can only be used with variable - lvalue (left value). + * Square brackets can be used for pointer arithmetic. - * '=' can only be used with variable or '*' (pointer - indirection) lvalue. + * '=' and = are supported. - * Function calls are supported with standard i386 calling - convention. Function pointers are supported with explicit - cast. Functions can be used before being declared. + * Function calls are supported with standard Linux calling + convention. Function pointers are supported. + Functions can be used before being declared. - - Types: only signed integer ('int') variables and functions can - be declared. Variables cannot be initialized in - declarations. Only old K&R function declarations are parsed - (implicit integer return value and no types on arguments). + - sizeof() is not supported. - - Any function or variable from the libc can be used because OTCC - uses the libc dynamic linker to resolve undefined symbols. + - Types: + + int, short, char, float, double + + pointers + + variables can be initialized in declarations. + + Only ANSI-style function declarations are supported. + - "..." is not supported. + - short is not supported + - const is not supported + - arrays are not supported + - long doubles are not supported + - structs are not supported + + - Unknown functions and variables are bound at compile time by calling + back to the caller. For the 'acc' command-line tool unknown functions + and variables are looked up using dlsym, to allow using many libc + functions and variables. - Instructions: blocks ('{' '}') are supported as in C. 'if' and 'else' can be used for tests. The 'while' and 'for' C constructs are supported for loops. 'break' can be used to exit loops. 'return' is used for the return value of a function. + - switch / case is not supported. + - goto and labels are not supported. + - continue is not supported. + - Identifiers are parsed the same way as C. Local variables are handled, but there is no local name space (not a problem if different names are used for local and global variables). @@ -49,16 +64,19 @@ Supported C language subset (read joint example 'otccex.c' to have - Numbers can be entered in decimal, hexadecimal ('0x' or '0X' prefix), or octal ('0' prefix). + - Float and double constants are supported. + - '#define' is supported without function like arguments. No macro recursion is tolerated. Other preprocessor directives are ignored. - - C Strings and C character constants are supported. Only '\n', - '\"', '\'' and '\\' escapes are recognized. + - C Strings and C character constants are supported. All ANSI C + character escapes are supported. - - Both C comments ( /* */ ) and C++ comments ( // ... end-of-line ) can be used. + - Both C comments ( /* */ ) and C++ comments ( // ... end-of-line ) are + supported. - - No error is displayed if an incorrect program is given. + - Some syntax errors are reported, others may cause a crash. - Memory: the code, data, and symbol sizes are limited to 100KB (it can be changed in the source code). diff --git a/libacc/acc.cpp b/libacc/acc.cpp index 676947e26..313bf1c50 100644 --- a/libacc/acc.cpp +++ b/libacc/acc.cpp @@ -133,13 +133,22 @@ public: class Compiler : public ErrorSink { typedef int tokenid_t; enum TypeTag { - TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE, - TY_POINTER, TY_FUNC, TY_PARAM + TY_INT, // 0 + TY_CHAR, // 1 + TY_SHORT, // 2 + TY_VOID, // 3 + TY_FLOAT, // 4 + TY_DOUBLE, // 5 + TY_POINTER, // 6 + TY_ARRAY, // 7 + TY_STRUCT, // 8 + TY_FUNC, // 9 + TY_PARAM // 10 }; struct Type { TypeTag tag; - tokenid_t id; // For function arguments + tokenid_t id; // For function arguments (stores length for array) Type* pHead; Type* pTail; }; @@ -594,8 +603,18 @@ class Compiler : public ErrorSink { TypeTag collapseType(TypeTag tag) { static const TypeTag collapsedTag[] = { - TY_INT, TY_INT, TY_VOID, TY_FLOAT, TY_DOUBLE, TY_INT, - TY_VOID, TY_VOID}; + TY_INT, + TY_INT, + TY_INT, + TY_VOID, + TY_FLOAT, + TY_DOUBLE, + TY_INT, + TY_INT, + TY_VOID, + TY_VOID, + TY_VOID + }; return collapsedTag[tag]; } @@ -1093,6 +1112,9 @@ class Compiler : public ErrorSink { case TY_FLOAT: o4(0xE5820000); // str r0, [r2] break; + case TY_SHORT: + o4(0xE1C200B0); // strh r0, [r2] + break; case TY_CHAR: o4(0xE5C20000); // strb r0, [r2] break; @@ -1115,6 +1137,9 @@ class Compiler : public ErrorSink { case TY_FLOAT: o4(0xE5900000); // ldr r0, [r0] break; + case TY_SHORT: + o4(0xE1D000F0); // ldrsh r0, [r0] + break; case TY_CHAR: o4(0xE5D00000); // ldrb r0, [r0] break; @@ -1378,6 +1403,8 @@ class Compiler : public ErrorSink { switch(pType->tag) { case TY_CHAR: return 1; + case TY_SHORT: + return 1; case TY_DOUBLE: return 8; default: @@ -1392,6 +1419,8 @@ class Compiler : public ErrorSink { switch(pType->tag) { case TY_INT: return 4; + case TY_SHORT: + return 2; case TY_CHAR: return 1; default: @@ -2095,6 +2124,9 @@ class Compiler : public ErrorSink { case TY_INT: o(0x0189); /* movl %eax/%al, (%ecx) */ break; + case TY_SHORT: + o(0x018966); /* movw %ax, (%ecx) */ + break; case TY_CHAR: o(0x0188); /* movl %eax/%al, (%ecx) */ break; @@ -2119,6 +2151,10 @@ class Compiler : public ErrorSink { case TY_INT: o2(0x008b); /* mov (%eax), %eax */ break; + case TY_SHORT: + o(0xbf0f); /* movswl (%eax), %eax */ + ob(0); + break; case TY_CHAR: o(0xbe0f); /* movsbl (%eax), %eax */ ob(0); /* add zero in code */ @@ -2288,6 +2324,8 @@ class Compiler : public ErrorSink { switch (pType->tag) { case TY_CHAR: return 1; + case TY_SHORT: + return 2; default: return 4; } @@ -2300,6 +2338,8 @@ class Compiler : public ErrorSink { switch(pType->tag) { case TY_INT: return 4; + case TY_SHORT: + return 2; case TY_CHAR: return 1; default: @@ -3158,6 +3198,7 @@ class Compiler : public ErrorSink { // Prebuilt types, makes things slightly faster. Type* mkpInt; // int + Type* mkpShort; // short Type* mkpChar; // char Type* mkpVoid; // void Type* mkpFloat; @@ -4013,7 +4054,8 @@ class Compiler : public ErrorSink { pGen->pushR0(); pGen->loadR0FromR0(); int tag = pGen->getR0Type()->tag; - if (!(tag == TY_INT || tag == TY_CHAR || tag == TY_POINTER)) { + if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR || + tag == TY_POINTER)) { error("++/-- illegal for this type. %d", tag); } if (isPost) { @@ -4262,6 +4304,9 @@ class Compiler : public ErrorSink { case TY_INT: buffer.appendCStr("int"); break; + case TY_SHORT: + buffer.appendCStr("short"); + break; case TY_CHAR: buffer.appendCStr("char"); break; @@ -4283,6 +4328,8 @@ class Compiler : public ErrorSink { switch (tag) { case TY_INT: break; + case TY_SHORT: + break; case TY_CHAR: break; case TY_VOID: @@ -4347,6 +4394,8 @@ class Compiler : public ErrorSink { Type* pType; if (tok == TOK_INT) { pType = mkpInt; + } else if (tok == TOK_SHORT) { + pType = mkpShort; } else if (tok == TOK_CHAR) { pType = mkpChar; } else if (tok == TOK_VOID) { @@ -4844,6 +4893,7 @@ public: void createPrimitiveTypes() { mkpInt = createType(TY_INT, NULL, NULL); + mkpShort = createType(TY_SHORT, NULL, NULL); mkpChar = createType(TY_CHAR, NULL, NULL); mkpVoid = createType(TY_VOID, NULL, NULL); mkpFloat = createType(TY_FLOAT, NULL, NULL); diff --git a/libacc/tests/data/short.c b/libacc/tests/data/short.c new file mode 100644 index 000000000..5e222f33a --- /dev/null +++ b/libacc/tests/data/short.c @@ -0,0 +1,6 @@ +short a = 3; +int main() { + short* b = &a; + *b = *b - 5; + return a; +} diff --git a/libacc/tests/runtimeTest.cpp b/libacc/tests/runtimeTest.cpp index d59e1d1d8..55bf877ed 100644 --- a/libacc/tests/runtimeTest.cpp +++ b/libacc/tests/runtimeTest.cpp @@ -30,6 +30,8 @@ void run(ScriptPtr scriptFn) { extern "C" void accDisassemble(ACCscript* script); +int globalVar; + void op_int(int a) { printf("op_int(%d)\n", a); } @@ -46,6 +48,7 @@ const char* text = "void op_int(int a);\n" " float e, float f, float g, float h,\n" " float i, float j, float k, float l);\n" "void script() {\n" + " globalVar += 3;\n" " op_int(123);\n" " op_float12(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0);\n" "}\n"; @@ -57,6 +60,9 @@ ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) { if (strcmp("op_float12", name) == 0) { return (ACCvoid*) op_float12; } + if (strcmp("globalVar", name) == 0) { + return (ACCvoid*) &globalVar; + } return (ACCvoid*) dlsym(RTLD_DEFAULT, name); } @@ -98,7 +104,9 @@ int main(int argc, char** argv) { fprintf(stderr, "Could not find script: %d\n", result); } else { fprintf(stderr, "Executing script:\n"); + globalVar = 17; run(scriptPointer); + fprintf(stderr, "After script globalVar = %d\n", globalVar); } diff --git a/libacc/tests/test.py b/libacc/tests/test.py index 7bcbdd4dc..a3114adba 100644 --- a/libacc/tests/test.py +++ b/libacc/tests/test.py @@ -380,6 +380,11 @@ arg: 12 Errors: 0 2D Errors: 0 result: 0 +""","""""") + + def testShort(self): + self.compileCheck(["-R", "data/short.c"], """Executing compiled code: +result: -2 ""","""""") if __name__ == '__main__':