# HG changeset patch # User John Tsiombikas # Date 1426391264 -7200 # Node ID 10f07b308aab9c6ade37dc2d09d767e6cad74d65 tutor2.txt completed diff -r 000000000000 -r 10f07b308aab .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sun Mar 15 05:47:44 2015 +0200 @@ -0,0 +1,5 @@ +\.o$ +\.s$ +\.swp$ +^test$ +^a\.out$ diff -r 000000000000 -r 10f07b308aab COMPILE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/COMPILE Sun Mar 15 05:47:44 2015 +0200 @@ -0,0 +1,5 @@ +#!/bin/sh + +./test >out.s && \ + as --32 -o out.o out.s && \ + ld -m elf_i386 out.o diff -r 000000000000 -r 10f07b308aab Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Sun Mar 15 05:47:44 2015 +0200 @@ -0,0 +1,12 @@ +src = $(wildcard src/*.c) +obj = $(src:.c=.o) +bin = test + +CFLAGS = -pedantic -Wall -g + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff -r 000000000000 -r 10f07b308aab RUN --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RUN Sun Mar 15 05:47:44 2015 +0200 @@ -0,0 +1,3 @@ +#!/bin/sh + +./a.out; echo $? diff -r 000000000000 -r 10f07b308aab src/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.c Sun Mar 15 05:47:44 2015 +0200 @@ -0,0 +1,230 @@ +#include +#include +#include +#include + +void init(void); +void expression(void); +void term(void); +void factor(void); +void add(void); +void sub(void); +void mul(void); +void divide(void); +void get_char(void); +void match(char c); +char get_name(void); +char get_num(void); +void stop(const char *s, ...); +void expected(const char *s); +void emit(const char *fmt, ...); +void vemit(const char *fmt, va_list ap); +void emitln(const char *fmt, ...); +int is_addsub(char c); + +FILE *infile, *outfile; +char look; + +static const char *prologue = + "\t.globl _start\n" + "_start:\n" + "\tcall main\n" + "\tmov %eax, %ebx\n" + "\tmov $1, %eax\n" + "\tint $0x80\n" + "main:\n" + "\t# ---- START ----\n"; + +static const char *epilogue = "\t# ---- END ----\n\tret\n"; + +int main(void) +{ + infile = stdin; + outfile = stdout; + + init(); + /* output prologue */ + fputs(prologue, outfile); + + expression(); + + /* output epilogue */ + fputs(epilogue, outfile); + return 0; +} + +void init(void) +{ + get_char(); +} + +void expression(void) +{ + if(is_addsub(look)) { + emitln("xor %%eax, %%eax"); + } else { + term(); + } + + while(is_addsub(look)) { + emitln("push %%eax"); + switch(look) { + case '+': + add(); + break; + case '-': + sub(); + break; + default: + expected("addop"); + } + } +} + +void term(void) +{ + factor(); + while(look == '*' || look == '/') { + emitln("push %%eax"); + switch(look) { + case '*': + mul(); + break; + case '/': + divide(); + break; + default: + expected("mulop"); + } + } +} + +void factor(void) +{ + if(look == '(') { + match('('); + expression(); + match(')'); + } else { + emitln("mov $%c, %%eax", get_num()); + } +} + +void add(void) +{ + match('+'); + term(); + emitln("pop %%ebx"); + emitln("add %%ebx, %%eax"); +} + +void sub(void) +{ + match('-'); + term(); + emitln("pop %%ebx"); + emitln("sub %%ebx, %%eax"); + emitln("neg %%eax"); +} + +void mul(void) +{ + match('*'); + factor(); + emitln("pop %%ebx"); + emitln("imul %%ebx"); +} + +void divide(void) +{ + match('/'); + factor(); + emitln("mov %%eax, %%ebx"); + emitln("pop %%eax"); + emitln("idiv %%ebx"); +} + +void get_char(void) +{ + look = fgetc(infile); +} + +void match(char c) +{ + if(look == c) { + get_char(); + } else { + char s[2] = {0, 0}; + s[0] = c; + expected(s); + } +} + +char get_name(void) +{ + char res; + if(!isalpha(look)) { + expected("name"); + } + res = toupper(look); + get_char(); + return res; +} + +char get_num(void) +{ + char res; + if(!isdigit(look)) { + expected("integer"); + } + res = look; + get_char(); + return res; +} + +void stop(const char *s, ...) +{ + va_list ap; + + fprintf(stderr, "error: "); + va_start(ap, s); + vfprintf(stderr, s, ap); + va_end(ap); + fputc('\n', stderr); + + abort(); +} + +void expected(const char *s) +{ + stop("%s expected", s); +} + +void emit(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vemit(fmt, ap); + va_end(ap); +} + +void vemit(const char *fmt, va_list ap) +{ + fputc('\t', outfile); + vfprintf(outfile, fmt, ap); +} + +void emitln(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vemit(fmt, ap); + va_end(ap); + fputc('\n', outfile); +} + + +int is_addsub(char c) +{ + return c == '+' || c == '-'; +}