Add support for "short" data type.
This commit is contained in:
parent
029c7f81a9
commit
c9b8ffc389
|
@ -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 <op>= 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).
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
short a = 3;
|
||||
int main() {
|
||||
short* b = &a;
|
||||
*b = *b - 5;
|
||||
return a;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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__':
|
||||
|
|
Loading…
Reference in New Issue