Import aap@github's B compiler.
This commit is contained in:
parent
4f446467c8
commit
a69045c0e4
22
lang/b/distr/LICENSE
Normal file
22
lang/b/distr/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013-2016 aap
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
15
lang/b/distr/Makefile
Normal file
15
lang/b/distr/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
CFLAGS=-Wall -Wextra
|
||||||
|
b: b0.o b1.o
|
||||||
|
cc b0.o b1.o -o b
|
||||||
|
b0.o: b0.c b.h
|
||||||
|
b1.o: b1.c b.h
|
||||||
|
|
||||||
|
libs:
|
||||||
|
./abc -c brt.s lib.b
|
||||||
|
|
||||||
|
install: b abc
|
||||||
|
cp abc $(HOME)/bin
|
||||||
|
|
||||||
|
%.o: %.s
|
||||||
|
as --32 $^ -o $@
|
||||||
|
|
53
lang/b/distr/README.md
Normal file
53
lang/b/distr/README.md
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
A B Compiler
|
||||||
|
============
|
||||||
|
|
||||||
|
abc is a compiler for the [B Programming Language](http://en.wikipedia.org/wiki/B_(programming_language)) that targets x86\_32 processors. It is currently tested under Linux but should work (or at least be easily ported) to other UNIX-like systems. The code is based on [an early C compiler (last1120c)](http://www.cs.bell-labs.com/who/dmr/primevalC.html) by Dennis Ritchie.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
* [The Programming Language B](http://9p.io/cm/cs/who/dmr/bintro.html)
|
||||||
|
|
||||||
|
* [B Reference by Ken Thompson](http://9p.io/cm/cs/who/dmr/kbman.html) describes a presumably earlier variant of B, which is slightly different from the one described above. The compiler cannot understand it, but I plan to implement a compatibility mode (the differences are minor).
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Since B was first implemented for machines with word addressing, some hacking was required to make it work on the byte addressed x86. Addresses filled in by the linker are always byte addresses, so pointers to these addresses are collectively stored at the end of the .data section and are then converted to word addresses at runtime, before main() is called.
|
||||||
|
|
||||||
|
The generated assembly is *very* inefficient, not even constant expressions are reduced at compile time. Also I/O is currently not buffered.
|
||||||
|
|
||||||
|
How to use
|
||||||
|
----------
|
||||||
|
|
||||||
|
The installation requires a little configuration:
|
||||||
|
'abc' is a frontend for the actual compiler which feels somewhat like gcc (it also handles assembling and linking). Before you can use it, set it's BDIR variable to the directory of the B compiler.
|
||||||
|
In the Makefile, change the directory of the 'install' rule to wherever you want your 'abc' file to reside.
|
||||||
|
Then type
|
||||||
|
|
||||||
|
make install libs
|
||||||
|
|
||||||
|
which compiles the compiler 'b', installs the 'abc' frontend and compiles the B runtime and library (brt.o and lib.o).
|
||||||
|
|
||||||
|
To compile and link a B program, simply type
|
||||||
|
|
||||||
|
abc -o outfile file1.b [file2.b ...]
|
||||||
|
|
||||||
|
If you want to compile and assemble only:
|
||||||
|
|
||||||
|
abc -c file1.b [file2.b ...]
|
||||||
|
|
||||||
|
or generate only the assembly:
|
||||||
|
|
||||||
|
abc -S file1.b [file2.b ...]
|
||||||
|
|
||||||
|
Examples of B programs are in the 'examples' directory, they are mostly from Brian Kernighan's tutorial.
|
||||||
|
|
||||||
|
Bugs
|
||||||
|
----
|
||||||
|
|
||||||
|
Since command line parameters aren't passed word-aligned, B can't handle them easily. brt.s copies the strings to another location and aligns them, the space is not dynamically allocated however and only 256 bytes are available by default.
|
||||||
|
|
||||||
|
The library is incomplete but has some of the most important functions.
|
||||||
|
|
||||||
|
I have only tested the compiler on an x86\_64 gentoo system.
|
95
lang/b/distr/abc
Executable file
95
lang/b/distr/abc
Executable file
|
@ -0,0 +1,95 @@
|
||||||
|
#!/bin/sh
|
||||||
|
BDIR="$HOME/abc"
|
||||||
|
objs="$BDIR/brt.o $BDIR/lib.o"
|
||||||
|
BC="$BDIR/b"
|
||||||
|
|
||||||
|
# compile in.b [out.s]
|
||||||
|
compile() {
|
||||||
|
if [ "${1##*.}" != "b" ]; then
|
||||||
|
echo "Error: can only compile b files" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cout=$2
|
||||||
|
[ "$cout" != "" ] || cout=${1%b}s
|
||||||
|
tmp1=`mktemp`; tmp2=`mktemp`
|
||||||
|
$BC $1 $tmp2 $tmp1
|
||||||
|
retval=$?
|
||||||
|
cat $tmp1 $tmp2 > $cout
|
||||||
|
rm $tmp1 $tmp2
|
||||||
|
[ $retval -eq 0 ] || rm $cout && return $retval
|
||||||
|
echo $cout
|
||||||
|
return $retval
|
||||||
|
}
|
||||||
|
|
||||||
|
# assemble in.{sb} [out.o]
|
||||||
|
assemble() {
|
||||||
|
atmp=""
|
||||||
|
ain=$1
|
||||||
|
aout=$2;
|
||||||
|
if [ "${1##*.}" = "b" ]; then
|
||||||
|
[ "$aout" != "" ] || aout=${ain%b}o
|
||||||
|
ain=`mktemp --suffix=.s`
|
||||||
|
compile $1 $ain >/dev/null || return 1
|
||||||
|
atmp="foo"
|
||||||
|
elif [ "${1##*.}" = "s" ]; then
|
||||||
|
[ "$aout" != "" ] || aout=${ain%s}o
|
||||||
|
else
|
||||||
|
echo "Error: can only compile b and s files" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
as --32 -g $ain -o $aout
|
||||||
|
[ "$atmp" != "" ] && rm $ain
|
||||||
|
echo $aout
|
||||||
|
}
|
||||||
|
|
||||||
|
out=""
|
||||||
|
action="link"
|
||||||
|
while getopts "o:Sc" o
|
||||||
|
do case "$o" in
|
||||||
|
o) out="$OPTARG";;
|
||||||
|
S) action=compile;;
|
||||||
|
c) action=assemble;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $(($OPTIND - 1))
|
||||||
|
|
||||||
|
# ignore -o option if more than one file given and not linking objs
|
||||||
|
if [ $# -gt 1 ]; then
|
||||||
|
if [ "$action" != "link" ]; then
|
||||||
|
out=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ $# -ne 1 ] && havelist=yes
|
||||||
|
tmpobjs=""
|
||||||
|
for i in $@; do
|
||||||
|
if [ "$action" != "link" ]; then
|
||||||
|
[ "$havelist" = "yes" ] && echo $i:
|
||||||
|
$action $i $out >/dev/null
|
||||||
|
[ $? -eq 0 ] || break=1
|
||||||
|
else
|
||||||
|
if [ "${i##*.}" = "o" ]; then
|
||||||
|
objs="$objs $i"
|
||||||
|
else
|
||||||
|
[ "$havelist" = "yes" ] && echo $i:
|
||||||
|
ltmp=`mktemp --suffix=.o`
|
||||||
|
tmpobjs="$tmpobjs $ltmp"
|
||||||
|
assemble $i $ltmp >/dev/null
|
||||||
|
[ $? -eq 0 ] || break=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ $break ]; then
|
||||||
|
[ "$tmpobjs" = "" ] || rm $tmpobjs
|
||||||
|
echo "Error" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$action" = "link" ]; then
|
||||||
|
if [ "$out" = "" ]; then
|
||||||
|
out="-o a.out"
|
||||||
|
else
|
||||||
|
out="-o $out"
|
||||||
|
fi
|
||||||
|
ld -m elf_i386 -T $BDIR/link.ld $out $objs $tmpobjs
|
||||||
|
rm $tmpobjs
|
||||||
|
fi
|
164
lang/b/distr/b.h
Normal file
164
lang/b/distr/b.h
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define NCPS 8 /* chars per symbol */
|
||||||
|
#define NCPW 4 /* chars per word */
|
||||||
|
#define ALIGN 4 /* Passed directly to the assembler's .align */
|
||||||
|
#define HSHSIZ 400 /* hash table size */
|
||||||
|
#define SWSIZ 230 /* switch table size */
|
||||||
|
#define CMSIZ 40 /* symbol stack size */
|
||||||
|
#define SSIZE 20 /* operator and precedence stack size */
|
||||||
|
#define OSSIZ 300*8 /* space for expression tree */
|
||||||
|
|
||||||
|
#define EOS 04 /* end of string marker */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Holds a B symbol.
|
||||||
|
* class is one of the storage classes below.
|
||||||
|
* offset is used depending on class.
|
||||||
|
*/
|
||||||
|
struct hshtab {
|
||||||
|
int class;
|
||||||
|
int offset;
|
||||||
|
int dim;
|
||||||
|
struct hshtab *next;
|
||||||
|
char name[NCPS+1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tnode {
|
||||||
|
int op;
|
||||||
|
int value;
|
||||||
|
struct tnode *tr1;
|
||||||
|
struct tnode *tr2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct swtab {
|
||||||
|
int swlab;
|
||||||
|
int swval;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hshtab hshtab[HSHSIZ];
|
||||||
|
int hshused;
|
||||||
|
int eof;
|
||||||
|
int peekc;
|
||||||
|
char ctab[128];
|
||||||
|
struct hshtab *bsym;
|
||||||
|
struct hshtab *paraml, *parame;
|
||||||
|
int cval;
|
||||||
|
int isn;
|
||||||
|
char symbuf[NCPS+1];
|
||||||
|
FILE *sbufp;
|
||||||
|
int stack;
|
||||||
|
struct tnode **cp;
|
||||||
|
int *space;
|
||||||
|
int ospace[OSSIZ];
|
||||||
|
int retlab;
|
||||||
|
int nerror;
|
||||||
|
struct swtab swtab[SWSIZ];
|
||||||
|
struct swtab *swp;
|
||||||
|
int deflab;
|
||||||
|
extern int contlab;
|
||||||
|
extern int brklab;
|
||||||
|
|
||||||
|
extern int opdope[];
|
||||||
|
extern int line;
|
||||||
|
extern int peeksym, peeksym2;
|
||||||
|
|
||||||
|
void error(char *s, ...);
|
||||||
|
void printtoken(int tok, FILE *out);
|
||||||
|
struct tnode * block(int op, int value, struct tnode *tr1, struct tnode *tr2);
|
||||||
|
void rcexpr(struct tnode *tr);
|
||||||
|
void cbranch(struct tnode *t, int lab, int val);
|
||||||
|
void jump(int lab);
|
||||||
|
void label(int l);
|
||||||
|
|
||||||
|
#define EOFC 0
|
||||||
|
#define SEMI 1
|
||||||
|
#define LBRACE 2
|
||||||
|
#define RBRACE 3
|
||||||
|
#define LBRACK 4
|
||||||
|
#define RBRACK 5
|
||||||
|
#define LPARN 6
|
||||||
|
#define RPARN 7
|
||||||
|
#define COLON 8
|
||||||
|
#define COMMA 9
|
||||||
|
|
||||||
|
#define MCALL 15
|
||||||
|
#define CALL 16
|
||||||
|
#define DECBEF 17
|
||||||
|
#define INCBEF 18
|
||||||
|
#define DECAFT 19
|
||||||
|
#define INCAFT 20
|
||||||
|
#define EXCLA 21
|
||||||
|
#define NEG 22
|
||||||
|
#define AMPER 23
|
||||||
|
#define STAR 24
|
||||||
|
#define QUEST 25
|
||||||
|
|
||||||
|
#define PLUS 30
|
||||||
|
#define MINUS 31
|
||||||
|
#define MOD 32
|
||||||
|
#define TIMES 33
|
||||||
|
#define DIVIDE 34
|
||||||
|
#define OR 35
|
||||||
|
#define AND 36
|
||||||
|
#define LSHIFT 37
|
||||||
|
#define RSHIFT 38
|
||||||
|
#define EQUAL 39
|
||||||
|
#define NEQUAL 40
|
||||||
|
#define LESSEQ 41
|
||||||
|
#define LESS 42
|
||||||
|
#define GREATEQ 43
|
||||||
|
#define GREAT 44
|
||||||
|
|
||||||
|
#define ASSIGN 49
|
||||||
|
#define ASPLUS 50
|
||||||
|
#define ASMINUS 51
|
||||||
|
#define ASMOD 52
|
||||||
|
#define ASTIMES 53
|
||||||
|
#define ASDIV 54
|
||||||
|
#define ASOR 55
|
||||||
|
#define ASAND 56
|
||||||
|
#define ASLSH 57
|
||||||
|
#define ASRSH 58
|
||||||
|
#define ASEQUAL 59
|
||||||
|
#define ASNEQL 60
|
||||||
|
#define ASLEQ 61
|
||||||
|
#define ASLESS 62
|
||||||
|
#define ASGTQ 63
|
||||||
|
#define ASGREAT 64
|
||||||
|
|
||||||
|
#define CON 65
|
||||||
|
#define STRING 66
|
||||||
|
#define NAME 67
|
||||||
|
#define KEYW 68
|
||||||
|
|
||||||
|
#define SQUOTE 121
|
||||||
|
#define DQUOTE 122
|
||||||
|
#define NEWLN 123
|
||||||
|
#define SPACE 124
|
||||||
|
#define LETTER 125
|
||||||
|
#define DIGIT 126
|
||||||
|
#define UNKN 127
|
||||||
|
|
||||||
|
#define SEOF 200
|
||||||
|
|
||||||
|
/* storage classes */
|
||||||
|
#define AUTO 1
|
||||||
|
#define EXTERN 2
|
||||||
|
#define INTERN 3
|
||||||
|
#define ARG 4
|
||||||
|
#define KEYWF 5
|
||||||
|
|
||||||
|
/* keywords */
|
||||||
|
#define CASE 3
|
||||||
|
#define IF 4
|
||||||
|
#define ELSE 5
|
||||||
|
#define WHILE 6
|
||||||
|
#define SWITCH 7
|
||||||
|
#define GOTO 8
|
||||||
|
#define RETURN 9
|
||||||
|
#define DEFAULT 10
|
||||||
|
#define BREAK 11
|
||||||
|
|
1277
lang/b/distr/b0.c
Normal file
1277
lang/b/distr/b0.c
Normal file
File diff suppressed because it is too large
Load diff
334
lang/b/distr/b1.c
Normal file
334
lang/b/distr/b1.c
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
#include "b.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Code generation (x86 assembly)
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
push(void)
|
||||||
|
{
|
||||||
|
printf("\tpush\t%%eax\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pop(char *s)
|
||||||
|
{
|
||||||
|
printf("\tpop\t%%%s\n", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
binary(struct tnode *tr)
|
||||||
|
{
|
||||||
|
rcexpr(tr->tr1);
|
||||||
|
push();
|
||||||
|
rcexpr(tr->tr2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pushargs(struct tnode *tr)
|
||||||
|
{
|
||||||
|
int stk;
|
||||||
|
|
||||||
|
if (tr == NULL)
|
||||||
|
return 0;
|
||||||
|
if (tr->op == COMMA) {
|
||||||
|
rcexpr(tr->tr2);
|
||||||
|
push();
|
||||||
|
stk = pushargs(tr->tr1);
|
||||||
|
return stk+NCPW;
|
||||||
|
}
|
||||||
|
rcexpr(tr);
|
||||||
|
push();
|
||||||
|
return NCPW;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lvalexp(struct tnode *tr)
|
||||||
|
{
|
||||||
|
struct hshtab *bs;
|
||||||
|
char memloc[64];
|
||||||
|
|
||||||
|
switch (tr->op) {
|
||||||
|
|
||||||
|
case DECBEF:
|
||||||
|
case INCBEF:
|
||||||
|
case DECAFT:
|
||||||
|
case INCAFT:
|
||||||
|
if (tr->tr1->op == STAR) {
|
||||||
|
rcexpr(tr->tr1->tr1);
|
||||||
|
printf("\tmov\t%%eax,%%ebx\n");
|
||||||
|
sprintf(memloc,"(,%%ebx,4)");
|
||||||
|
} else { /* NAME, checked in "build" */
|
||||||
|
bs = (struct hshtab *) tr->tr1->tr1;
|
||||||
|
if (bs->class == EXTERN)
|
||||||
|
sprintf(memloc,"_%s", bs->name);
|
||||||
|
else if (bs->class == AUTO)
|
||||||
|
sprintf(memloc,"%d(%%ebp)", bs->offset);
|
||||||
|
else
|
||||||
|
goto classerror;
|
||||||
|
}
|
||||||
|
if (tr->op == DECBEF || tr->op == INCBEF) {
|
||||||
|
printf("\t%s\t%s\n", tr->op == DECBEF ? "decl" : "incl",
|
||||||
|
memloc);
|
||||||
|
printf("\tmov\t%s,%%eax\n", memloc);
|
||||||
|
} else {
|
||||||
|
printf("\tmov\t%s,%%eax\n", memloc);
|
||||||
|
printf("\t%s\t%s\n", tr->op == DECAFT ? "decl" : "incl",
|
||||||
|
memloc);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case ASSIGN:
|
||||||
|
rcexpr(tr->tr2);
|
||||||
|
if (tr->tr1->op == STAR) {
|
||||||
|
push();
|
||||||
|
rcexpr(tr->tr1->tr1);
|
||||||
|
pop("ebx");
|
||||||
|
printf("\tmov\t%%ebx,(,%%eax,4)\n");
|
||||||
|
} else { /* NAME */
|
||||||
|
bs = (struct hshtab *) tr->tr1->tr1;
|
||||||
|
if (bs->class == EXTERN)
|
||||||
|
printf("\tmov\t%%eax,_%s\n", bs->name);
|
||||||
|
else if (bs->class == AUTO)
|
||||||
|
printf("\tmov\t%%eax,%d(%%ebp)\n", bs->offset);
|
||||||
|
else
|
||||||
|
goto classerror;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case ASPLUS:
|
||||||
|
case ASMINUS:
|
||||||
|
case ASMOD:
|
||||||
|
case ASTIMES:
|
||||||
|
case ASDIV:
|
||||||
|
case ASOR:
|
||||||
|
case ASAND:
|
||||||
|
case ASLSH:
|
||||||
|
case ASRSH:
|
||||||
|
case ASEQUAL:
|
||||||
|
case ASNEQL:
|
||||||
|
case ASLEQ:
|
||||||
|
case ASLESS:
|
||||||
|
case ASGTQ:
|
||||||
|
case ASGREAT:
|
||||||
|
tr->op -= ASPLUS-PLUS;
|
||||||
|
rcexpr(block(ASSIGN,0,tr->tr1,tr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
classerror:
|
||||||
|
error("Storage class");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rcexpr(struct tnode *tr)
|
||||||
|
{
|
||||||
|
int o1, o2;
|
||||||
|
int stk;
|
||||||
|
struct hshtab *bs;
|
||||||
|
|
||||||
|
if (tr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (opdope[tr->op]&02) {
|
||||||
|
lvalexp(tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (tr->op) {
|
||||||
|
|
||||||
|
case CON:
|
||||||
|
printf("\tmov\t$%d,%%eax\n", tr->value);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case STRING:
|
||||||
|
printf("\tmov\t$L%d,%%eax\n", tr->value);
|
||||||
|
printf("\tshr\t$2,%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case NAME: /* only rvalue */
|
||||||
|
bs = (struct hshtab *) tr->tr1;
|
||||||
|
if (bs->class == EXTERN)
|
||||||
|
printf("\tmov\t_%s,%%eax\n", bs->name);
|
||||||
|
else if (bs->class == AUTO)
|
||||||
|
printf("\tmov\t%d(%%ebp),%%eax\n", bs->offset);
|
||||||
|
else
|
||||||
|
goto classerror;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case CALL:
|
||||||
|
stk = pushargs(tr->tr2);
|
||||||
|
rcexpr(tr->tr1);
|
||||||
|
printf("\tshl\t$2,%%eax\n");
|
||||||
|
printf("\tcall\t*%%eax\n");
|
||||||
|
if (stk)
|
||||||
|
printf("\tadd\t$%d,%%esp\n",stk);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case AMPER:
|
||||||
|
bs = (struct hshtab *) tr->tr1->tr1;
|
||||||
|
if (bs->class == EXTERN) {
|
||||||
|
printf("\tmov\t$_%s,%%eax\n", bs->name);
|
||||||
|
printf("\tshr\t$2,%%eax\n");
|
||||||
|
} else if (bs->class == AUTO) {
|
||||||
|
printf("\tlea\t%d(%%ebp),%%eax\n", bs->offset);
|
||||||
|
printf("\tshr\t$2,%%eax\n");
|
||||||
|
} else
|
||||||
|
goto classerror;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case STAR: /* only rvalue */
|
||||||
|
rcexpr(tr->tr1);
|
||||||
|
printf("\tmov\t(,%%eax,4),%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case PLUS:
|
||||||
|
binary(tr);
|
||||||
|
pop("ebx");
|
||||||
|
printf("\tadd\t%%ebx,%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case MINUS:
|
||||||
|
binary(tr);
|
||||||
|
printf("\tmov\t%%eax,%%ebx\n");
|
||||||
|
pop("eax");
|
||||||
|
printf("\tsub\t%%ebx,%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case TIMES:
|
||||||
|
binary(tr);
|
||||||
|
pop("ebx");
|
||||||
|
printf("\tmul\t%%ebx\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case DIVIDE:
|
||||||
|
binary(tr);
|
||||||
|
printf("\tmov\t%%eax,%%ebx\n");
|
||||||
|
pop("eax");
|
||||||
|
printf("\txor\t%%edx,%%edx\n");
|
||||||
|
printf("\tdiv\t%%ebx\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case MOD:
|
||||||
|
binary(tr);
|
||||||
|
printf("\tmov\t%%eax,%%ebx\n");
|
||||||
|
pop("eax");
|
||||||
|
printf("\txor\t%%edx,%%edx\n");
|
||||||
|
printf("\tdiv\t%%ebx\n");
|
||||||
|
printf("\tmov\t%%edx,%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case AND:
|
||||||
|
binary(tr);
|
||||||
|
pop("ebx");
|
||||||
|
printf("\tand\t%%ebx,%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case OR:
|
||||||
|
binary(tr);
|
||||||
|
pop("ebx");
|
||||||
|
printf("\tor\t%%ebx,%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case LSHIFT:
|
||||||
|
binary(tr);
|
||||||
|
printf("\tmov\t%%eax,%%ecx\n");
|
||||||
|
pop("eax");
|
||||||
|
printf("\tshl\t%%cl,%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case RSHIFT:
|
||||||
|
binary(tr);
|
||||||
|
printf("\tmov\t%%eax,%%ecx\n");
|
||||||
|
pop("eax");
|
||||||
|
printf("\tshr\t%%cl,%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case EQUAL:
|
||||||
|
case NEQUAL:
|
||||||
|
case LESS:
|
||||||
|
case LESSEQ:
|
||||||
|
case GREAT:
|
||||||
|
case GREATEQ:
|
||||||
|
binary(tr);
|
||||||
|
pop("ebx");
|
||||||
|
printf("\tcmp\t%%eax,%%ebx\n");
|
||||||
|
switch (tr->op) {
|
||||||
|
case EQUAL:
|
||||||
|
printf("\tsete\t%%al\n");
|
||||||
|
break;
|
||||||
|
case NEQUAL:
|
||||||
|
printf("\tsetne\t%%al\n");
|
||||||
|
break;
|
||||||
|
case LESS:
|
||||||
|
printf("\tsetl\t%%al\n");
|
||||||
|
break;
|
||||||
|
case LESSEQ:
|
||||||
|
printf("\tsetle\t%%al\n");
|
||||||
|
break;
|
||||||
|
case GREAT:
|
||||||
|
printf("\tsetg\t%%al\n");
|
||||||
|
break;
|
||||||
|
case GREATEQ:
|
||||||
|
printf("\tsetge\t%%al\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("\tmovzb\t%%al,%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case EXCLA:
|
||||||
|
rcexpr(tr->tr1);
|
||||||
|
printf("\ttest\t%%eax,%%eax\n");
|
||||||
|
printf("\tsete\t%%al\n");
|
||||||
|
printf("\tmovzb\t%%al,%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case NEG:
|
||||||
|
rcexpr(tr->tr1);
|
||||||
|
printf("\tneg\t%%eax\n");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case QUEST:
|
||||||
|
cbranch(tr->tr1, o1=isn++, 0);
|
||||||
|
rcexpr(tr->tr2->tr1);
|
||||||
|
jump(o2 = isn++);
|
||||||
|
label(o1);
|
||||||
|
rcexpr(tr->tr2->tr2);
|
||||||
|
label(o2);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error("Can't print tree (op: %d)", tr->op);
|
||||||
|
}
|
||||||
|
|
||||||
|
classerror:
|
||||||
|
error("Storage class");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prints the tree in RPN, for debugging */
|
||||||
|
/*
|
||||||
|
void
|
||||||
|
rcexpr(struct tnode *tr)
|
||||||
|
{
|
||||||
|
struct hshtab *bs;
|
||||||
|
|
||||||
|
if (tr == NULL)
|
||||||
|
printf("(NULL) ");
|
||||||
|
else if (tr->op == CON)
|
||||||
|
printf("%d ", tr->value);
|
||||||
|
else if (tr->op == STRING)
|
||||||
|
printf("s(L%d) ", tr->value);
|
||||||
|
else if (tr->op == NAME) {
|
||||||
|
bs = (struct hshtab *)tr->tr1;
|
||||||
|
if (bs->class == AUTO)
|
||||||
|
printf("%s(%d) ", bs->name, bs->offset);
|
||||||
|
else
|
||||||
|
printf("%s ", bs->name);
|
||||||
|
} else {
|
||||||
|
rcexpr(tr->tr1);
|
||||||
|
if (opdope[tr->op]&01)
|
||||||
|
rcexpr(tr->tr2);
|
||||||
|
printtoken(tr->op, stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
151
lang/b/distr/brt.s
Normal file
151
lang/b/distr/brt.s
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
.globl _argv
|
||||||
|
.data
|
||||||
|
.align 4
|
||||||
|
.comm argstr,256,4
|
||||||
|
_argv: .long 0
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl start
|
||||||
|
start:
|
||||||
|
# clear bss (could be done better)
|
||||||
|
# is it actually necessary?
|
||||||
|
mov $__bss,%eax
|
||||||
|
1:
|
||||||
|
movb $0,(%eax)
|
||||||
|
inc %eax
|
||||||
|
cmp $__ebss,%eax
|
||||||
|
jbe 1b
|
||||||
|
|
||||||
|
# copy command line args (can't use them directly, not aligned)
|
||||||
|
mov %esp,%eax
|
||||||
|
shr $2,%eax
|
||||||
|
mov %eax,_argv
|
||||||
|
mov (%esp),%ecx # number of arguments
|
||||||
|
mov $argstr,%edi
|
||||||
|
1:
|
||||||
|
mov (%esp,%ecx,4),%esi
|
||||||
|
mov %edi,%eax
|
||||||
|
shr $2,%eax
|
||||||
|
mov %eax,(%esp,%ecx,4)
|
||||||
|
call cpystr
|
||||||
|
loop 1b
|
||||||
|
|
||||||
|
call bsymbs
|
||||||
|
mov _main,%eax
|
||||||
|
shl $2,%eax
|
||||||
|
call *%eax
|
||||||
|
mov %eax,%ebx
|
||||||
|
mov $1,%eax
|
||||||
|
int $0x80
|
||||||
|
|
||||||
|
# copy string from esi to edi and convert '\0' to B's '*e', align edi
|
||||||
|
cpystr:
|
||||||
|
mov (%esi),%al
|
||||||
|
test %al,%al
|
||||||
|
jz 1f
|
||||||
|
mov %al,(%edi)
|
||||||
|
inc %edi
|
||||||
|
inc %esi
|
||||||
|
jmp cpystr
|
||||||
|
1:
|
||||||
|
movb $04,(%edi)
|
||||||
|
inc %edi
|
||||||
|
add $3,%edi
|
||||||
|
and $~3,%edi
|
||||||
|
ret
|
||||||
|
|
||||||
|
# shift addresses filled in by the linker 2 bits to the right
|
||||||
|
# so B only ever sees word addresses
|
||||||
|
bsymbs:
|
||||||
|
mov $__bsymb,%eax
|
||||||
|
1:
|
||||||
|
cmp $__ebsymb,%eax
|
||||||
|
jge 1f
|
||||||
|
mov (%eax),%ebx
|
||||||
|
mov (%ebx),%ecx
|
||||||
|
shr $2,%ecx
|
||||||
|
mov %ecx,(%ebx)
|
||||||
|
add $4,%eax
|
||||||
|
jmp 1b
|
||||||
|
1:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.globl retrn
|
||||||
|
retrn:
|
||||||
|
mov %ebp,%esp
|
||||||
|
pop %ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
# handle switch table:
|
||||||
|
# eax has the value, ebx the address of the switch table
|
||||||
|
.globl bswitch
|
||||||
|
bswitch:
|
||||||
|
xor %ecx,%ecx
|
||||||
|
1:
|
||||||
|
mov (%ebx,%ecx,8),%edx
|
||||||
|
mov 4(%ebx,%ecx,8),%edi
|
||||||
|
test %edi,%edi
|
||||||
|
jz 1f # default (last in table)
|
||||||
|
cmp %eax,%edx
|
||||||
|
je 2f
|
||||||
|
inc %ecx
|
||||||
|
jmp 1b
|
||||||
|
1:
|
||||||
|
jmp *%edx
|
||||||
|
2:
|
||||||
|
jmp *%edi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Library functions in assembly
|
||||||
|
#
|
||||||
|
.globl _exit
|
||||||
|
.data
|
||||||
|
.align 4
|
||||||
|
.section .bsymb; .long _exit; .data
|
||||||
|
_exit: .long 1f
|
||||||
|
.text
|
||||||
|
.align 4
|
||||||
|
1: mov $1,%eax
|
||||||
|
mov $0,%ebx
|
||||||
|
int $0x80
|
||||||
|
|
||||||
|
.globl _write
|
||||||
|
.data
|
||||||
|
.align 4
|
||||||
|
.section .bsymb; .long _write; .data
|
||||||
|
_write: .long 1f
|
||||||
|
.text
|
||||||
|
.align 4
|
||||||
|
1: mov 4(%esp),%ebx
|
||||||
|
mov 8(%esp),%ecx
|
||||||
|
shl $2,%ecx
|
||||||
|
mov 12(%esp),%edx
|
||||||
|
mov $4,%eax
|
||||||
|
int $0x80
|
||||||
|
ret
|
||||||
|
|
||||||
|
.globl _read
|
||||||
|
.data
|
||||||
|
.align 4
|
||||||
|
.section .bsymb; .long _read; .data
|
||||||
|
_read: .long 1f
|
||||||
|
.text
|
||||||
|
.align 4
|
||||||
|
1: mov 4(%esp),%ebx
|
||||||
|
mov 8(%esp),%ecx
|
||||||
|
shl $2,%ecx
|
||||||
|
mov 12(%esp),%edx
|
||||||
|
mov $3,%eax
|
||||||
|
int $0x80
|
||||||
|
ret
|
||||||
|
|
||||||
|
.globl _inv
|
||||||
|
.data
|
||||||
|
.align 4
|
||||||
|
.section .bsymb; .long _inv; .data
|
||||||
|
_inv: .long 1f
|
||||||
|
.text
|
||||||
|
.align 4
|
||||||
|
1: mov 4(%esp),%eax
|
||||||
|
not %eax
|
||||||
|
ret
|
7
lang/b/distr/examples/1_var.b
Normal file
7
lang/b/distr/examples/1_var.b
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
main() {
|
||||||
|
auto a, b, c, sum;
|
||||||
|
|
||||||
|
a = 1; b = 2; c = 3;
|
||||||
|
sum = a+b+c;
|
||||||
|
putnumb(sum);
|
||||||
|
}
|
9
lang/b/distr/examples/2_ext.b
Normal file
9
lang/b/distr/examples/2_ext.b
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
main() {
|
||||||
|
extrn a, b, c;
|
||||||
|
putchar(a); putchar(b); putchar(c); putchar('!*n');
|
||||||
|
}
|
||||||
|
|
||||||
|
a 'hell';
|
||||||
|
b 'o, w';
|
||||||
|
c 'orld';
|
||||||
|
|
13
lang/b/distr/examples/3_fun.b
Normal file
13
lang/b/distr/examples/3_fun.b
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
main() {
|
||||||
|
extrn a, b, c, d;
|
||||||
|
put2char(a,b);
|
||||||
|
put2char(c,d);
|
||||||
|
}
|
||||||
|
|
||||||
|
put2char(x,y) {
|
||||||
|
putchar(x);
|
||||||
|
putchar(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
a 'hell'; b 'o, w'; c 'orld'; d '!*n';
|
||||||
|
|
7
lang/b/distr/examples/4_goto.b
Normal file
7
lang/b/distr/examples/4_goto.b
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
main() {
|
||||||
|
auto c;
|
||||||
|
read:
|
||||||
|
c= getchar();
|
||||||
|
putchar(c);
|
||||||
|
if(c != '*n') goto read;
|
||||||
|
}
|
10
lang/b/distr/examples/5_while.b
Normal file
10
lang/b/distr/examples/5_while.b
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
main() {
|
||||||
|
auto c;
|
||||||
|
while (1) {
|
||||||
|
while ( (c=getchar()) != ' ')
|
||||||
|
if (putchar(c) == '*n') exit();
|
||||||
|
putchar( '*n' );
|
||||||
|
while ( (c=getchar()) == ' '); /* skip blanks */
|
||||||
|
if (putchar(c)=='*n') exit();
|
||||||
|
}
|
||||||
|
}
|
10
lang/b/distr/examples/printargs.b
Normal file
10
lang/b/distr/examples/printargs.b
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
main() {
|
||||||
|
extrn argv;
|
||||||
|
auto i;
|
||||||
|
|
||||||
|
i = 1;
|
||||||
|
printf("%d args:*n", argv[0]);
|
||||||
|
while (i <= argv[0])
|
||||||
|
printf("%s*n", argv[i++]);
|
||||||
|
return(0);
|
||||||
|
}
|
111
lang/b/distr/lib.b
Normal file
111
lang/b/distr/lib.b
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
char(s, n)
|
||||||
|
return((s[n/4]>>8*(n%4))&0377); /* s[n/4] */
|
||||||
|
|
||||||
|
lchar(s, n, char) {
|
||||||
|
auto i;
|
||||||
|
i = 8*(n%4);
|
||||||
|
char = (char&0377)<<i;
|
||||||
|
i = inv(0377<<i);
|
||||||
|
s[(n/4)*4] = s[n/4]&i | char;
|
||||||
|
}
|
||||||
|
|
||||||
|
putchar(char) {
|
||||||
|
auto c, i;
|
||||||
|
|
||||||
|
c = char;
|
||||||
|
i = 4;
|
||||||
|
while ((c&0377) != '*e' & (c&0377) != '*0' & i != 0) {
|
||||||
|
i--;
|
||||||
|
c =>> 8;
|
||||||
|
}
|
||||||
|
write(1, &char, 4-i);
|
||||||
|
return(char);
|
||||||
|
}
|
||||||
|
|
||||||
|
getchar() {
|
||||||
|
auto char;
|
||||||
|
|
||||||
|
char = 0;
|
||||||
|
read(1, &char, 1);
|
||||||
|
return(char);
|
||||||
|
}
|
||||||
|
|
||||||
|
printn(n,b) {
|
||||||
|
extrn putchar;
|
||||||
|
auto a;
|
||||||
|
|
||||||
|
if (a = n/b)
|
||||||
|
printn(a, b);
|
||||||
|
putchar(char("0123456789ABCDEF", n%b));
|
||||||
|
}
|
||||||
|
|
||||||
|
putnumb(n) {
|
||||||
|
printn(n,10);
|
||||||
|
putchar('*n');
|
||||||
|
}
|
||||||
|
|
||||||
|
putstr(s) {
|
||||||
|
auto c, i;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while ((c = char(s,i++)) != '*e')
|
||||||
|
putchar(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
getstr(s) {
|
||||||
|
auto c, i;
|
||||||
|
|
||||||
|
while ((c = getchar()) != '*n')
|
||||||
|
lchar(s,i++,c);
|
||||||
|
lchar(s,i,'*e');
|
||||||
|
return(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(fmt, x1,x2,x3,x4,x5,x6,x7,x8,x9) {
|
||||||
|
extrn printn, char, putchar;
|
||||||
|
auto adx, x, c, i, j;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
adx = &x1;
|
||||||
|
loop:
|
||||||
|
while((c=char(fmt,i++)) != '%') {
|
||||||
|
if(c == '*e')
|
||||||
|
return;
|
||||||
|
putchar(c);
|
||||||
|
}
|
||||||
|
x = *adx++;
|
||||||
|
switch (c = char(fmt,i++)) {
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
case 'o':
|
||||||
|
if(x < 0) {
|
||||||
|
x = -x;
|
||||||
|
putchar('-');
|
||||||
|
}
|
||||||
|
printn(x, c=='o'?8:10);
|
||||||
|
goto loop;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
if(x < 0) {
|
||||||
|
x = -x;
|
||||||
|
putchar('-');
|
||||||
|
}
|
||||||
|
printn(x, 16);
|
||||||
|
goto loop;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
putchar(x);
|
||||||
|
goto loop;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
j = 0;
|
||||||
|
while((c=char(x,j++)) != '*e')
|
||||||
|
putchar(c);
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
putchar('%');
|
||||||
|
i--;
|
||||||
|
adx--;
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
21
lang/b/distr/link.ld
Normal file
21
lang/b/distr/link.ld
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
OUTPUT_FORMAT("elf32-i386")
|
||||||
|
OUTPUT_ARCH(i386)
|
||||||
|
|
||||||
|
ENTRY(start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x400000;
|
||||||
|
.text : { *(.text) }
|
||||||
|
. = 0x8000000;
|
||||||
|
.data : {
|
||||||
|
*(.data)
|
||||||
|
__bsymb = .;
|
||||||
|
*(.bsymb)
|
||||||
|
__ebsymb = .;
|
||||||
|
}
|
||||||
|
. = ALIGN(16);
|
||||||
|
__bss = .;
|
||||||
|
.bss : { *(.bss) }
|
||||||
|
__ebss = .;
|
||||||
|
}
|
Loading…
Reference in a new issue