Assembler x86 (32-bit) - 142 bytes
The 142 bytes are the compiled size (not the source code size, which is larger). Note that for assembler the size of the compiled code is not dependend on the compiler used but it should always be 142 bytes.
The calling convention is "_cdecl" so you can call the function from C:
const char *strCalc(const char *num1,
char operation, const char *num2, char *bufferEnd);
The function accepts negative inputs (such as "-AB") and zero (" "). However malformed inputs might crash the program!
The last argument points to the LAST byte of a buffer used to store the sring because C does not support strings without pre-allocated buffers.
The function returns the pointer to the string (somewhere in the buffer). The function may be called the following way:
#include <stdio.h>
const char *strCalc(const char *num1, char operation, const char *num2, char *bufferEnd);
main(int argc,char **argv)
{
char buf[21];
puts(strCalc(argv[1],argv[2][0],argv[3],buf+20));
}
Here is the actual function (Linux users: Replace "_strCalc" by "strCalc"):
.globl _strCalc
.text
_strCalc:
push %ebx
push %esi
push %edi
mov 16(%esp), %esi
call loadNum
push %ebx
mov 28(%esp), %esi
call loadNum
pop %eax
# This assumes that the operation is ONLY +, * or -!
cmpb $0x2B, 20(%esp)
je isPlus
jb isMultiply
sub %ebx, %eax
jmp calcDone
isPlus:
add %ebx, %eax
jmp calcDone
isMultiply:
xor %edx, %edx
imul %ebx
calcDone:
push %eax
mov 32(%esp), %edi
std
xor %al, %al
stosb
pop %eax
call writeOut
mov %al, (%edi)
mov %edi, %eax
inc %eax
pop %edi
pop %esi
pop %ebx
# Needed due to MSVCRT.DLL bug!
cld
ret
# Write EAX to the buffer
# EDI points to the last character to be
# written (the terminating NUL has already been written)
# Returns: EDI pointer to the first character!
writeOut:
test %eax, %eax
jnz notZero
mov $0x20, %al
stosb
ret
notZero:
jns notNegative
neg %eax
call writeOut
mov $0x2D,%al
stosb
ret
notNegative:
xor %edx, %edx
dec %eax
div %ecx
xchg %al, %dl
add $0x41, %al
stosb
xchg %al, %dl
test %eax, %eax
jnz notNegative
xchg %al, %dl
ret
# Load number from string ESI points to to EBX
# Destroys EAX, ECX, EDX
# Allows negative and zero inputs!
# Assumes syntactically correct numbers!
# Sets ECX to 26 (needed later!)
loadNum:
xor %ebx, %ebx
xor %eax, %eax
mov $26, %al
mov %eax, %ecx
nextLoad:
cld
lodsb
and $0xDF, %al
jz endOfLoad
sub $0x40, %al
jc negativeInput
xchg %eax, %ebx
mul %ecx
add %eax, %ebx
jmp nextLoad
negativeInput:
call loadNum
neg %ebx
endOfLoad:
ret