ある日、私はこの世界に幻想郷を持ち込むことができるでしょう
Some checks failed
Build / build (push) Has been cancelled

This commit is contained in:
2025-07-08 14:35:03 -03:00
parent 513c538fba
commit 02a2e94a89
73 changed files with 46 additions and 23699 deletions

577
Makefile
View File

@@ -26,18 +26,6 @@ endif
ifndef BUILD_SERVER
BUILD_SERVER =
endif
ifndef BUILD_GAME_SO
BUILD_GAME_SO =
endif
ifndef BUILD_GAME_QVM
BUILD_GAME_QVM =
endif
ifndef BUILD_BASEGAME
BUILD_BASEGAME =
endif
ifndef BUILD_MISSIONPACK
BUILD_MISSIONPACK=
endif
ifndef BUILD_RENDERER_OPENGL2
BUILD_RENDERER_OPENGL2=
endif
@@ -50,7 +38,7 @@ endif
# causing problems with keeping up to date with the repository.
#
#############################################################################
-include Makefile.OpenArena
-include Makefile.IA
-include Makefile.local
ifndef PLATFORM
@@ -116,14 +104,6 @@ ifndef BASEGAME_CFLAGS
BASEGAME_CFLAGS=
endif
ifndef MISSIONPACK
MISSIONPACK=missionpack
endif
ifndef MISSIONPACK_CFLAGS
MISSIONPACK_CFLAGS=-DMISSIONPACK
endif
ifndef COPYDIR
COPYDIR="/usr/local/games/quake3"
endif
@@ -271,13 +251,9 @@ OGGDIR=$(MOUNT_DIR)/libogg-1.3.1
OPUSDIR=$(MOUNT_DIR)/opus-1.1
OPUSFILEDIR=$(MOUNT_DIR)/opusfile-0.5
ZDIR=$(MOUNT_DIR)/zlib
Q3ASMDIR=$(MOUNT_DIR)/tools/asm
LBURGDIR=$(MOUNT_DIR)/tools/lcc/lburg
Q3CPPDIR=$(MOUNT_DIR)/tools/lcc/cpp
Q3LCCETCDIR=$(MOUNT_DIR)/tools/lcc/etc
Q3LCCSRCDIR=$(MOUNT_DIR)/tools/lcc/src
LOKISETUPDIR=misc/setup
NSISDIR=misc/nsis
ifeq ($(SDL_VERSION),2)
SDLHDIR=$(MOUNT_DIR)/SDL2
else
@@ -857,12 +833,18 @@ ifeq ($(PLATFORM),netbsd)
THREAD_LIBS=-lpthread
BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes
CLIENT_CFLAGS += $(SDL_CFLAGS)
CLIENT_LIBS += $(SDL_LIBS) $(shell pkg-config --libs gl libcurl libjpeg libxmp ogg opus speex)
ifeq ($(ARCH),x86)
HAVE_VM_COMPILED=true
endif
BUILD_CLIENT = 0
USE_INTERNAL_JPEG=0
USE_INTERNAL_OGG=0
USE_INTERNAL_OPUS=0
USE_INTERNAL_SPEEX=0
USE_INTERNAL_ZLIB=0
else # ifeq netbsd
#############################################################################
@@ -1015,36 +997,6 @@ ifneq ($(BUILD_CLIENT),0)
endif
endif
ifneq ($(BUILD_GAME_SO),0)
ifneq ($(BUILD_BASEGAME),0)
TARGETS += \
$(B)/$(BASEGAME)/cgame$(SHLIBNAME) \
$(B)/$(BASEGAME)/qagame$(SHLIBNAME) \
$(B)/$(BASEGAME)/ui$(SHLIBNAME)
endif
ifneq ($(BUILD_MISSIONPACK),0)
TARGETS += \
$(B)/$(MISSIONPACK)/cgame$(SHLIBNAME) \
$(B)/$(MISSIONPACK)/qagame$(SHLIBNAME) \
$(B)/$(MISSIONPACK)/ui$(SHLIBNAME)
endif
endif
ifneq ($(BUILD_GAME_QVM),0)
ifneq ($(BUILD_BASEGAME),0)
TARGETS += \
$(B)/$(BASEGAME)/vm/cgame.qvm \
$(B)/$(BASEGAME)/vm/qagame.qvm \
$(B)/$(BASEGAME)/vm/ui.qvm
endif
ifneq ($(BUILD_MISSIONPACK),0)
TARGETS += \
$(B)/$(MISSIONPACK)/vm/cgame.qvm \
$(B)/$(MISSIONPACK)/vm/qagame.qvm \
$(B)/$(MISSIONPACK)/vm/ui.qvm
endif
endif
ifeq ($(USE_OPENAL),1)
CLIENT_CFLAGS += -DUSE_OPENAL
ifeq ($(USE_OPENAL_DLOPEN),1)
@@ -1364,201 +1316,6 @@ makedirs:
@if [ ! -d $(B)/renderer_oa ];then $(MKDIR) $(B)/renderer_oa;fi
@if [ ! -d $(B)/renderersoft ];then $(MKDIR) $(B)/renderersoft;fi
@if [ ! -d $(B)/ded ];then $(MKDIR) $(B)/ded;fi
@if [ ! -d $(B)/$(BASEGAME) ];then $(MKDIR) $(B)/$(BASEGAME);fi
@if [ ! -d $(B)/$(BASEGAME)/cgame ];then $(MKDIR) $(B)/$(BASEGAME)/cgame;fi
@if [ ! -d $(B)/$(BASEGAME)/game ];then $(MKDIR) $(B)/$(BASEGAME)/game;fi
@if [ ! -d $(B)/$(BASEGAME)/ui ];then $(MKDIR) $(B)/$(BASEGAME)/ui;fi
@if [ ! -d $(B)/$(BASEGAME)/qcommon ];then $(MKDIR) $(B)/$(BASEGAME)/qcommon;fi
@if [ ! -d $(B)/$(BASEGAME)/vm ];then $(MKDIR) $(B)/$(BASEGAME)/vm;fi
@if [ ! -d $(B)/$(MISSIONPACK) ];then $(MKDIR) $(B)/$(MISSIONPACK);fi
@if [ ! -d $(B)/$(MISSIONPACK)/cgame ];then $(MKDIR) $(B)/$(MISSIONPACK)/cgame;fi
@if [ ! -d $(B)/$(MISSIONPACK)/game ];then $(MKDIR) $(B)/$(MISSIONPACK)/game;fi
@if [ ! -d $(B)/$(MISSIONPACK)/ui ];then $(MKDIR) $(B)/$(MISSIONPACK)/ui;fi
@if [ ! -d $(B)/$(MISSIONPACK)/qcommon ];then $(MKDIR) $(B)/$(MISSIONPACK)/qcommon;fi
@if [ ! -d $(B)/$(MISSIONPACK)/vm ];then $(MKDIR) $(B)/$(MISSIONPACK)/vm;fi
@if [ ! -d $(B)/tools ];then $(MKDIR) $(B)/tools;fi
@if [ ! -d $(B)/tools/asm ];then $(MKDIR) $(B)/tools/asm;fi
@if [ ! -d $(B)/tools/etc ];then $(MKDIR) $(B)/tools/etc;fi
@if [ ! -d $(B)/tools/rcc ];then $(MKDIR) $(B)/tools/rcc;fi
@if [ ! -d $(B)/tools/cpp ];then $(MKDIR) $(B)/tools/cpp;fi
@if [ ! -d $(B)/tools/lburg ];then $(MKDIR) $(B)/tools/lburg;fi
#############################################################################
# QVM BUILD TOOLS
#############################################################################
ifndef TOOLS_CC
# A compiler which probably produces native binaries
TOOLS_CC = gcc
endif
TOOLS_OPTIMIZE = -g -Wall -fno-strict-aliasing
TOOLS_CFLAGS += $(TOOLS_OPTIMIZE) \
-DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" \
-I$(Q3LCCSRCDIR) \
-I$(LBURGDIR)
TOOLS_LIBS =
TOOLS_LDFLAGS =
ifeq ($(GENERATE_DEPENDENCIES),1)
TOOLS_CFLAGS += -MMD
endif
define DO_TOOLS_CC
$(echo_cmd) "TOOLS_CC $<"
$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) -o $@ -c $<
endef
define DO_TOOLS_CC_DAGCHECK
$(echo_cmd) "TOOLS_CC_DAGCHECK $<"
$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) -Wno-unused -o $@ -c $<
endef
LBURG = $(B)/tools/lburg/lburg$(TOOLS_BINEXT)
DAGCHECK_C = $(B)/tools/rcc/dagcheck.c
Q3RCC = $(B)/tools/q3rcc$(TOOLS_BINEXT)
Q3CPP = $(B)/tools/q3cpp$(TOOLS_BINEXT)
Q3LCC = $(B)/tools/q3lcc$(TOOLS_BINEXT)
Q3ASM = $(B)/tools/q3asm$(TOOLS_BINEXT)
LBURGOBJ= \
$(B)/tools/lburg/lburg.o \
$(B)/tools/lburg/gram.o
$(B)/tools/lburg/%.o: $(LBURGDIR)/%.c
$(DO_TOOLS_CC)
$(LBURG): $(LBURGOBJ)
$(echo_cmd) "LD $@"
$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
Q3RCCOBJ = \
$(B)/tools/rcc/alloc.o \
$(B)/tools/rcc/bind.o \
$(B)/tools/rcc/bytecode.o \
$(B)/tools/rcc/dag.o \
$(B)/tools/rcc/dagcheck.o \
$(B)/tools/rcc/decl.o \
$(B)/tools/rcc/enode.o \
$(B)/tools/rcc/error.o \
$(B)/tools/rcc/event.o \
$(B)/tools/rcc/expr.o \
$(B)/tools/rcc/gen.o \
$(B)/tools/rcc/init.o \
$(B)/tools/rcc/inits.o \
$(B)/tools/rcc/input.o \
$(B)/tools/rcc/lex.o \
$(B)/tools/rcc/list.o \
$(B)/tools/rcc/main.o \
$(B)/tools/rcc/null.o \
$(B)/tools/rcc/output.o \
$(B)/tools/rcc/prof.o \
$(B)/tools/rcc/profio.o \
$(B)/tools/rcc/simp.o \
$(B)/tools/rcc/stmt.o \
$(B)/tools/rcc/string.o \
$(B)/tools/rcc/sym.o \
$(B)/tools/rcc/symbolic.o \
$(B)/tools/rcc/trace.o \
$(B)/tools/rcc/tree.o \
$(B)/tools/rcc/types.o
$(DAGCHECK_C): $(LBURG) $(Q3LCCSRCDIR)/dagcheck.md
$(echo_cmd) "LBURG $(Q3LCCSRCDIR)/dagcheck.md"
$(Q)$(LBURG) $(Q3LCCSRCDIR)/dagcheck.md $@
$(B)/tools/rcc/dagcheck.o: $(DAGCHECK_C)
$(DO_TOOLS_CC_DAGCHECK)
$(B)/tools/rcc/%.o: $(Q3LCCSRCDIR)/%.c
$(DO_TOOLS_CC)
$(Q3RCC): $(Q3RCCOBJ)
$(echo_cmd) "LD $@"
$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
Q3CPPOBJ = \
$(B)/tools/cpp/cpp.o \
$(B)/tools/cpp/lex.o \
$(B)/tools/cpp/nlist.o \
$(B)/tools/cpp/tokens.o \
$(B)/tools/cpp/macro.o \
$(B)/tools/cpp/eval.o \
$(B)/tools/cpp/include.o \
$(B)/tools/cpp/hideset.o \
$(B)/tools/cpp/getopt.o \
$(B)/tools/cpp/unix.o
$(B)/tools/cpp/%.o: $(Q3CPPDIR)/%.c
$(DO_TOOLS_CC)
$(Q3CPP): $(Q3CPPOBJ)
$(echo_cmd) "LD $@"
$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
Q3LCCOBJ = \
$(B)/tools/etc/lcc.o \
$(B)/tools/etc/bytecode.o
$(B)/tools/etc/%.o: $(Q3LCCETCDIR)/%.c
$(DO_TOOLS_CC)
$(Q3LCC): $(Q3LCCOBJ) $(Q3RCC) $(Q3CPP)
$(echo_cmd) "LD $@"
$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $(Q3LCCOBJ) $(TOOLS_LIBS)
define DO_Q3LCC
$(echo_cmd) "Q3LCC $<"
$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -o $@ $<
endef
define DO_CGAME_Q3LCC
$(echo_cmd) "CGAME_Q3LCC $<"
$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DCGAME -o $@ $<
endef
define DO_GAME_Q3LCC
$(echo_cmd) "GAME_Q3LCC $<"
$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DQAGAME -o $@ $<
endef
define DO_UI_Q3LCC
$(echo_cmd) "UI_Q3LCC $<"
$(Q)$(Q3LCC) $(BASEGAME_CFLAGS) -DUI -o $@ $<
endef
define DO_Q3LCC_MISSIONPACK
$(echo_cmd) "Q3LCC_MISSIONPACK $<"
$(Q)$(Q3LCC) $(MISSIONPACK_CFLAGS) -o $@ $<
endef
define DO_CGAME_Q3LCC_MISSIONPACK
$(echo_cmd) "CGAME_Q3LCC_MISSIONPACK $<"
$(Q)$(Q3LCC) $(MISSIONPACK_CFLAGS) -DCGAME -o $@ $<
endef
define DO_GAME_Q3LCC_MISSIONPACK
$(echo_cmd) "GAME_Q3LCC_MISSIONPACK $<"
$(Q)$(Q3LCC) $(MISSIONPACK_CFLAGS) -DQAGAME -o $@ $<
endef
define DO_UI_Q3LCC_MISSIONPACK
$(echo_cmd) "UI_Q3LCC_MISSIONPACK $<"
$(Q)$(Q3LCC) $(MISSIONPACK_CFLAGS) -DUI -o $@ $<
endef
Q3ASMOBJ = \
$(B)/tools/asm/q3asm.o \
$(B)/tools/asm/cmdlib.o
$(B)/tools/asm/%.o: $(Q3ASMDIR)/%.c
$(DO_TOOLS_CC)
$(Q3ASM): $(Q3ASMOBJ)
$(echo_cmd) "LD $@"
$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS)
#############################################################################
# CLIENT/SERVER
@@ -2389,292 +2146,6 @@ $(B)/$(SERVERBIN)$(FULLBINEXT): $(Q3DOBJ)
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(Q3DOBJ) $(LIBS)
#############################################################################
## BASEQ3 CGAME
#############################################################################
Q3CGOBJ_ = \
$(B)/$(BASEGAME)/cgame/cg_main.o \
$(B)/$(BASEGAME)/cgame/bg_misc.o \
$(B)/$(BASEGAME)/cgame/bg_pmove.o \
$(B)/$(BASEGAME)/cgame/bg_slidemove.o \
$(B)/$(BASEGAME)/cgame/bg_lib.o \
$(B)/$(BASEGAME)/cgame/cg_consolecmds.o \
$(B)/$(BASEGAME)/cgame/cg_draw.o \
$(B)/$(BASEGAME)/cgame/cg_drawtools.o \
$(B)/$(BASEGAME)/cgame/cg_effects.o \
$(B)/$(BASEGAME)/cgame/cg_ents.o \
$(B)/$(BASEGAME)/cgame/cg_event.o \
$(B)/$(BASEGAME)/cgame/cg_info.o \
$(B)/$(BASEGAME)/cgame/cg_localents.o \
$(B)/$(BASEGAME)/cgame/cg_marks.o \
$(B)/$(BASEGAME)/cgame/cg_particles.o \
$(B)/$(BASEGAME)/cgame/cg_players.o \
$(B)/$(BASEGAME)/cgame/cg_playerstate.o \
$(B)/$(BASEGAME)/cgame/cg_predict.o \
$(B)/$(BASEGAME)/cgame/cg_scoreboard.o \
$(B)/$(BASEGAME)/cgame/cg_servercmds.o \
$(B)/$(BASEGAME)/cgame/cg_snapshot.o \
$(B)/$(BASEGAME)/cgame/cg_view.o \
$(B)/$(BASEGAME)/cgame/cg_weapons.o \
\
$(B)/$(BASEGAME)/qcommon/q_math.o \
$(B)/$(BASEGAME)/qcommon/q_shared.o
Q3CGOBJ = $(Q3CGOBJ_) $(B)/$(BASEGAME)/cgame/cg_syscalls.o
Q3CGVMOBJ = $(Q3CGOBJ_:%.o=%.asm)
$(B)/$(BASEGAME)/cgame$(SHLIBNAME): $(Q3CGOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3CGOBJ)
$(B)/$(BASEGAME)/vm/cgame.qvm: $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM)
$(echo_cmd) "Q3ASM $@"
$(Q)$(Q3ASM) -o $@ $(Q3CGVMOBJ) $(CGDIR)/cg_syscalls.asm
#############################################################################
## MISSIONPACK CGAME
#############################################################################
MPCGOBJ_ = \
$(B)/$(MISSIONPACK)/cgame/cg_main.o \
$(B)/$(MISSIONPACK)/cgame/bg_misc.o \
$(B)/$(MISSIONPACK)/cgame/bg_pmove.o \
$(B)/$(MISSIONPACK)/cgame/bg_slidemove.o \
$(B)/$(MISSIONPACK)/cgame/bg_lib.o \
$(B)/$(MISSIONPACK)/cgame/cg_consolecmds.o \
$(B)/$(MISSIONPACK)/cgame/cg_newdraw.o \
$(B)/$(MISSIONPACK)/cgame/cg_draw.o \
$(B)/$(MISSIONPACK)/cgame/cg_drawtools.o \
$(B)/$(MISSIONPACK)/cgame/cg_effects.o \
$(B)/$(MISSIONPACK)/cgame/cg_ents.o \
$(B)/$(MISSIONPACK)/cgame/cg_event.o \
$(B)/$(MISSIONPACK)/cgame/cg_info.o \
$(B)/$(MISSIONPACK)/cgame/cg_localents.o \
$(B)/$(MISSIONPACK)/cgame/cg_marks.o \
$(B)/$(MISSIONPACK)/cgame/cg_particles.o \
$(B)/$(MISSIONPACK)/cgame/cg_players.o \
$(B)/$(MISSIONPACK)/cgame/cg_playerstate.o \
$(B)/$(MISSIONPACK)/cgame/cg_predict.o \
$(B)/$(MISSIONPACK)/cgame/cg_scoreboard.o \
$(B)/$(MISSIONPACK)/cgame/cg_servercmds.o \
$(B)/$(MISSIONPACK)/cgame/cg_snapshot.o \
$(B)/$(MISSIONPACK)/cgame/cg_view.o \
$(B)/$(MISSIONPACK)/cgame/cg_weapons.o \
$(B)/$(MISSIONPACK)/ui/ui_shared.o \
\
$(B)/$(MISSIONPACK)/qcommon/q_math.o \
$(B)/$(MISSIONPACK)/qcommon/q_shared.o
MPCGOBJ = $(MPCGOBJ_) $(B)/$(MISSIONPACK)/cgame/cg_syscalls.o
MPCGVMOBJ = $(MPCGOBJ_:%.o=%.asm)
$(B)/$(MISSIONPACK)/cgame$(SHLIBNAME): $(MPCGOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPCGOBJ)
$(B)/$(MISSIONPACK)/vm/cgame.qvm: $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm $(Q3ASM)
$(echo_cmd) "Q3ASM $@"
$(Q)$(Q3ASM) -o $@ $(MPCGVMOBJ) $(CGDIR)/cg_syscalls.asm
#############################################################################
## BASEQ3 GAME
#############################################################################
Q3GOBJ_ = \
$(B)/$(BASEGAME)/game/g_main.o \
$(B)/$(BASEGAME)/game/ai_chat.o \
$(B)/$(BASEGAME)/game/ai_cmd.o \
$(B)/$(BASEGAME)/game/ai_dmnet.o \
$(B)/$(BASEGAME)/game/ai_dmq3.o \
$(B)/$(BASEGAME)/game/ai_main.o \
$(B)/$(BASEGAME)/game/ai_team.o \
$(B)/$(BASEGAME)/game/ai_vcmd.o \
$(B)/$(BASEGAME)/game/bg_misc.o \
$(B)/$(BASEGAME)/game/bg_pmove.o \
$(B)/$(BASEGAME)/game/bg_slidemove.o \
$(B)/$(BASEGAME)/game/bg_lib.o \
$(B)/$(BASEGAME)/game/g_active.o \
$(B)/$(BASEGAME)/game/g_arenas.o \
$(B)/$(BASEGAME)/game/g_bot.o \
$(B)/$(BASEGAME)/game/g_client.o \
$(B)/$(BASEGAME)/game/g_cmds.o \
$(B)/$(BASEGAME)/game/g_combat.o \
$(B)/$(BASEGAME)/game/g_items.o \
$(B)/$(BASEGAME)/game/g_mem.o \
$(B)/$(BASEGAME)/game/g_misc.o \
$(B)/$(BASEGAME)/game/g_missile.o \
$(B)/$(BASEGAME)/game/g_mover.o \
$(B)/$(BASEGAME)/game/g_session.o \
$(B)/$(BASEGAME)/game/g_spawn.o \
$(B)/$(BASEGAME)/game/g_svcmds.o \
$(B)/$(BASEGAME)/game/g_target.o \
$(B)/$(BASEGAME)/game/g_team.o \
$(B)/$(BASEGAME)/game/g_trigger.o \
$(B)/$(BASEGAME)/game/g_utils.o \
$(B)/$(BASEGAME)/game/g_weapon.o \
\
$(B)/$(BASEGAME)/qcommon/q_math.o \
$(B)/$(BASEGAME)/qcommon/q_shared.o
Q3GOBJ = $(Q3GOBJ_) $(B)/$(BASEGAME)/game/g_syscalls.o
Q3GVMOBJ = $(Q3GOBJ_:%.o=%.asm)
$(B)/$(BASEGAME)/qagame$(SHLIBNAME): $(Q3GOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3GOBJ)
$(B)/$(BASEGAME)/vm/qagame.qvm: $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM)
$(echo_cmd) "Q3ASM $@"
$(Q)$(Q3ASM) -o $@ $(Q3GVMOBJ) $(GDIR)/g_syscalls.asm
#############################################################################
## MISSIONPACK GAME
#############################################################################
MPGOBJ_ = \
$(B)/$(MISSIONPACK)/game/g_main.o \
$(B)/$(MISSIONPACK)/game/ai_chat.o \
$(B)/$(MISSIONPACK)/game/ai_cmd.o \
$(B)/$(MISSIONPACK)/game/ai_dmnet.o \
$(B)/$(MISSIONPACK)/game/ai_dmq3.o \
$(B)/$(MISSIONPACK)/game/ai_main.o \
$(B)/$(MISSIONPACK)/game/ai_team.o \
$(B)/$(MISSIONPACK)/game/ai_vcmd.o \
$(B)/$(MISSIONPACK)/game/bg_misc.o \
$(B)/$(MISSIONPACK)/game/bg_pmove.o \
$(B)/$(MISSIONPACK)/game/bg_slidemove.o \
$(B)/$(MISSIONPACK)/game/bg_lib.o \
$(B)/$(MISSIONPACK)/game/g_active.o \
$(B)/$(MISSIONPACK)/game/g_arenas.o \
$(B)/$(MISSIONPACK)/game/g_bot.o \
$(B)/$(MISSIONPACK)/game/g_client.o \
$(B)/$(MISSIONPACK)/game/g_cmds.o \
$(B)/$(MISSIONPACK)/game/g_combat.o \
$(B)/$(MISSIONPACK)/game/g_items.o \
$(B)/$(MISSIONPACK)/game/g_mem.o \
$(B)/$(MISSIONPACK)/game/g_misc.o \
$(B)/$(MISSIONPACK)/game/g_missile.o \
$(B)/$(MISSIONPACK)/game/g_mover.o \
$(B)/$(MISSIONPACK)/game/g_session.o \
$(B)/$(MISSIONPACK)/game/g_spawn.o \
$(B)/$(MISSIONPACK)/game/g_svcmds.o \
$(B)/$(MISSIONPACK)/game/g_target.o \
$(B)/$(MISSIONPACK)/game/g_team.o \
$(B)/$(MISSIONPACK)/game/g_trigger.o \
$(B)/$(MISSIONPACK)/game/g_utils.o \
$(B)/$(MISSIONPACK)/game/g_weapon.o \
\
$(B)/$(MISSIONPACK)/qcommon/q_math.o \
$(B)/$(MISSIONPACK)/qcommon/q_shared.o
MPGOBJ = $(MPGOBJ_) $(B)/$(MISSIONPACK)/game/g_syscalls.o
MPGVMOBJ = $(MPGOBJ_:%.o=%.asm)
$(B)/$(MISSIONPACK)/qagame$(SHLIBNAME): $(MPGOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPGOBJ)
$(B)/$(MISSIONPACK)/vm/qagame.qvm: $(MPGVMOBJ) $(GDIR)/g_syscalls.asm $(Q3ASM)
$(echo_cmd) "Q3ASM $@"
$(Q)$(Q3ASM) -o $@ $(MPGVMOBJ) $(GDIR)/g_syscalls.asm
#############################################################################
## BASEQ3 UI
#############################################################################
Q3UIOBJ_ = \
$(B)/$(BASEGAME)/ui/ui_main.o \
$(B)/$(BASEGAME)/ui/bg_misc.o \
$(B)/$(BASEGAME)/ui/bg_lib.o \
$(B)/$(BASEGAME)/ui/ui_addbots.o \
$(B)/$(BASEGAME)/ui/ui_atoms.o \
$(B)/$(BASEGAME)/ui/ui_cdkey.o \
$(B)/$(BASEGAME)/ui/ui_cinematics.o \
$(B)/$(BASEGAME)/ui/ui_confirm.o \
$(B)/$(BASEGAME)/ui/ui_connect.o \
$(B)/$(BASEGAME)/ui/ui_controls2.o \
$(B)/$(BASEGAME)/ui/ui_credits.o \
$(B)/$(BASEGAME)/ui/ui_demo2.o \
$(B)/$(BASEGAME)/ui/ui_display.o \
$(B)/$(BASEGAME)/ui/ui_gameinfo.o \
$(B)/$(BASEGAME)/ui/ui_ingame.o \
$(B)/$(BASEGAME)/ui/ui_loadconfig.o \
$(B)/$(BASEGAME)/ui/ui_menu.o \
$(B)/$(BASEGAME)/ui/ui_mfield.o \
$(B)/$(BASEGAME)/ui/ui_mods.o \
$(B)/$(BASEGAME)/ui/ui_network.o \
$(B)/$(BASEGAME)/ui/ui_options.o \
$(B)/$(BASEGAME)/ui/ui_playermodel.o \
$(B)/$(BASEGAME)/ui/ui_players.o \
$(B)/$(BASEGAME)/ui/ui_playersettings.o \
$(B)/$(BASEGAME)/ui/ui_preferences.o \
$(B)/$(BASEGAME)/ui/ui_qmenu.o \
$(B)/$(BASEGAME)/ui/ui_removebots.o \
$(B)/$(BASEGAME)/ui/ui_saveconfig.o \
$(B)/$(BASEGAME)/ui/ui_serverinfo.o \
$(B)/$(BASEGAME)/ui/ui_servers2.o \
$(B)/$(BASEGAME)/ui/ui_setup.o \
$(B)/$(BASEGAME)/ui/ui_sound.o \
$(B)/$(BASEGAME)/ui/ui_sparena.o \
$(B)/$(BASEGAME)/ui/ui_specifyserver.o \
$(B)/$(BASEGAME)/ui/ui_splevel.o \
$(B)/$(BASEGAME)/ui/ui_sppostgame.o \
$(B)/$(BASEGAME)/ui/ui_spskill.o \
$(B)/$(BASEGAME)/ui/ui_startserver.o \
$(B)/$(BASEGAME)/ui/ui_team.o \
$(B)/$(BASEGAME)/ui/ui_teamorders.o \
$(B)/$(BASEGAME)/ui/ui_video.o \
\
$(B)/$(BASEGAME)/qcommon/q_math.o \
$(B)/$(BASEGAME)/qcommon/q_shared.o
Q3UIOBJ = $(Q3UIOBJ_) $(B)/$(MISSIONPACK)/ui/ui_syscalls.o
Q3UIVMOBJ = $(Q3UIOBJ_:%.o=%.asm)
$(B)/$(BASEGAME)/ui$(SHLIBNAME): $(Q3UIOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3UIOBJ)
$(B)/$(BASEGAME)/vm/ui.qvm: $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM)
$(echo_cmd) "Q3ASM $@"
$(Q)$(Q3ASM) -o $@ $(Q3UIVMOBJ) $(UIDIR)/ui_syscalls.asm
#############################################################################
## MISSIONPACK UI
#############################################################################
MPUIOBJ_ = \
$(B)/$(MISSIONPACK)/ui/ui_main.o \
$(B)/$(MISSIONPACK)/ui/ui_atoms.o \
$(B)/$(MISSIONPACK)/ui/ui_gameinfo.o \
$(B)/$(MISSIONPACK)/ui/ui_players.o \
$(B)/$(MISSIONPACK)/ui/ui_shared.o \
\
$(B)/$(MISSIONPACK)/ui/bg_misc.o \
$(B)/$(MISSIONPACK)/ui/bg_lib.o \
\
$(B)/$(MISSIONPACK)/qcommon/q_math.o \
$(B)/$(MISSIONPACK)/qcommon/q_shared.o
MPUIOBJ = $(MPUIOBJ_) $(B)/$(MISSIONPACK)/ui/ui_syscalls.o
MPUIVMOBJ = $(MPUIOBJ_:%.o=%.asm)
$(B)/$(MISSIONPACK)/ui$(SHLIBNAME): $(MPUIOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(MPUIOBJ)
$(B)/$(MISSIONPACK)/vm/ui.qvm: $(MPUIVMOBJ) $(UIDIR)/ui_syscalls.asm $(Q3ASM)
$(echo_cmd) "Q3ASM $@"
$(Q)$(Q3ASM) -o $@ $(MPUIVMOBJ) $(UIDIR)/ui_syscalls.asm
#############################################################################
## CLIENT/SERVER RULES
#############################################################################
@@ -2916,15 +2387,6 @@ STRINGOBJ = $(Q3R2STRINGOBJ)
copyfiles: release
@if [ ! -d $(COPYDIR)/$(BASEGAME) ]; then echo "You need to set COPYDIR to where your Quake3 data is!"; fi
ifneq ($(BUILD_GAME_SO),0)
ifneq ($(BUILD_BASEGAME),0)
-$(MKDIR) -p -m 0755 $(COPYDIR)/$(BASEGAME)
endif
ifneq ($(BUILD_MISSIONPACK),0)
-$(MKDIR) -p -m 0755 $(COPYDIR)/$(MISSIONPACK)
endif
endif
ifneq ($(BUILD_CLIENT),0)
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)$(FULLBINEXT)
ifneq ($(USE_RENDERER_DLOPEN),0)
@@ -2949,25 +2411,6 @@ ifneq ($(BUILD_SERVER),0)
fi
endif
ifneq ($(BUILD_GAME_SO),0)
ifneq ($(BUILD_BASEGAME),0)
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(BASEGAME)/cgame$(SHLIBNAME) \
$(COPYDIR)/$(BASEGAME)/.
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(BASEGAME)/qagame$(SHLIBNAME) \
$(COPYDIR)/$(BASEGAME)/.
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(BASEGAME)/ui$(SHLIBNAME) \
$(COPYDIR)/$(BASEGAME)/.
endif
ifneq ($(BUILD_MISSIONPACK),0)
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(MISSIONPACK)/cgame$(SHLIBNAME) \
$(COPYDIR)/$(MISSIONPACK)/.
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(MISSIONPACK)/qagame$(SHLIBNAME) \
$(COPYDIR)/$(MISSIONPACK)/.
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(MISSIONPACK)/ui$(SHLIBNAME) \
$(COPYDIR)/$(MISSIONPACK)/.
endif
endif
clean: clean-debug clean-release
ifeq ($(PLATFORM),mingw32)
@$(MAKE) -C $(NSISDIR) clean

View File

@@ -1,34 +1,20 @@
# Avoid making updates to this file unless you want to change defaults.
# Create a Makefile.local which is ignored by git for your local overrides
# that you don't want committed to git.
USE_GIT =0
# Defaults for OpenArena. You shouldn't need to modify this section
# Defaults for Illusion Arena. You shouldn't need to modify this section
# This is only the client/server engine so we don't build the QVM here.
# For the QVM game code, see https://gitea.pukeko.club/hifuu-club/illusion-arena
BUILD_STANDALONE=1
BUILD_CLIENT=1
BUILD_SERVER=1
BUILD_GAME_SO=0
BUILD_GAME_QVM=0
BUILD_BASEGAME=0
BUILD_MISSIONPACK=0
BASEGAME=baseoa
# VERSION=1.36+0.8.8
VERSION=3.0.0a
BASEGAME=baseia
VERSION=1.36+ia18
# OpenArena doesn't use opus yet
USE_CODEC_VORBIS=1
USE_CODEC_OPUS=0
ifndef USE_CODEC_XMP
USE_CODEC_OPUS=1
USE_CODEC_XMP=1
endif
# FLTO Test
OPTIMIZE += -flto
# This doesn't work with OpenArena yet
# This doesn't work with Illusion Arena yet
BUILD_RENDERER_OPENGL2=0
# You can disable the renderer libraries and build in the OA renderer by default
USE_RENDERER_DLOPEN=0
@@ -52,11 +38,10 @@ GLSL_BACKEND =1 # for the entire backend.
#Possible values "gnu90", "gnu99" and "gnu11". Note that the engine uses gnu-extensions. gnu90 is broken in the commit where this message is added. Travis does not support gnu11 at the moment.
CFLAGS+="-std=gnu99"
# You can change these although you probably don't need to
CLIENTBIN=openarena
SERVERBIN=oa_ded
COPYDIR=/usr/local/games/openarena
CLIENTBIN=illusionarena
SERVERBIN=ia_ded
COPYDIR=/usr/local/games/illusionarena
# DEBUG_CFLAGS=-ggdb -O0
@@ -68,4 +53,4 @@ COPYDIR=/usr/local/games/openarena
# V=1
#
# Build a zip -r9 file or Mac OSX release zip (make-macosx-app.sh)
# ARCHIVE=1
ARCHIVE=1

View File

@@ -1,8 +1,10 @@
# OpenArena Engine [![Build Status](https://travis-ci.org/OpenArena/engine.png?branch=master)](https://travis-ci.org/OpenArena/engine) #
# Illusion Arena Engine
This project is a fork of ioquake3 with OpenArena specific changes to the
This project is a fork of ioquake3 with Illusion Arena specific changes to the
client and server.
Itself, a fork of a fork.
## Building ##
This a standard ioquake3 build which they describe [here](http://wiki.ioquake3.org/Building_ioquake3)
@@ -16,7 +18,7 @@ the build dependencies for the "ioquake3" package.
```sh
$ sudo aptitude build-dep ioquake3
$ sudo apt-get install libsdl1.2-dev libxmp-dev
$ git clone https://github.com/OpenArena/engine.git
$ git clone https://gitea.pukeko.club/hifuu-club/illusion-arena-engine
$ cd engine
$ make
```
@@ -30,7 +32,7 @@ same directory to run it.
```sh
# Get this project or sign up on github and fork it
$ git clone https://github.com/OpenArena/engine.git
$ git clone https://gitea.pukeko.club/hifuu-club/illusion-arena-engine.git
$ cd engine
# Create a reference to the upstream project
@@ -48,25 +50,25 @@ select the renderer at runtime rather than compiling in one into the binary.
This feature is enabled by default. If you wish to disable it, uncomment
USE_RENDERER_DLOPEN=0 in Makefile.local. With ioquake3, this embeds the
opengl1 renderer. In OpenArena, it embeds the openarena1 renderer.
opengl1 renderer. In Illusion Arena, it embeds the openarena1 renderer.
When you start OpenArena, you can pass the name of the dynamic library to
When you start Illusion Arena, you can pass the name of the dynamic library to
load. ioquake3 assumes a naming convention renderer_*_.
Example:
```sh
# Enable the default OpenArena renderer with GLSL, bloom support and more.
# Enable the default Illusion Arena renderer with GLSL, bloom support and more.
# This is based on the renderergl1 code.
$ ./openarena.x86_64 +set cl_renderer openarena1
$ ./illusionarena.x86_64 +set cl_renderer openarena1
# Enable the default ioquake3 renderer (renderergl1).
# If you are having trouble with OA's renderer, this is a safe alternative.
$ ./openarena.x86_64 +set cl_renderer opengl1
$ ./illusionarena.x86_64 +set cl_renderer opengl1
# Enable renderergl2 which is now in upstream
# It doesn't work with OpenArena yet
$ ./openarena.x86_64 +set cl_renderer opengl2
# It doesn't work with Illusion Arena yet
$ ./illusionarena.x86_64 +set cl_renderer opengl2
```
## TODO ##
@@ -97,7 +99,13 @@ $ ./openarena.x86_64 +set cl_renderer opengl2
* Need help testing the SDL2 branch since ioquake3 is moving to SDL2
- sdl2 branch is considered finished in ioquake3 so it is a good base
- See experimental/latest-libraries-sdl2 branch in this repository to
test with OpenArena.
test with Illusion Arena.
## Changes from OpenArena/engine.git ##
* Modifications to the build system
* Improved support for NetBSD
* Skip building Quake VM files by default, which are not located here
## Changes from 0.8.8 release ##

View File

@@ -27,12 +27,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// A user mod should never modify this file
#ifdef STANDALONE
#define PRODUCT_NAME "OpenArena"
#define BASEGAME "baseoa"
#define CLIENT_WINDOW_TITLE "OpenArena"
#define CLIENT_WINDOW_MIN_TITLE "OA"
#define HOMEPATH_NAME_UNIX ".openarena"
#define HOMEPATH_NAME_WIN "OpenArena"
#define PRODUCT_NAME "Illusion Arena"
#define BASEGAME "baseia"
#define CLIENT_WINDOW_TITLE "Illusion Arena"
#define CLIENT_WINDOW_MIN_TITLE "IA"
#define HOMEPATH_NAME_UNIX ".illusionarena"
#define HOMEPATH_NAME_WIN "IllusionArena"
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
#define HOMEPATH_NAME_XDG HOMEPATH_NAME_WIN
#define GAMENAME_FOR_MASTER "Quake3Arena" // must NOT contain whitespace. No servers show up if you use "openarena"

View File

@@ -1,10 +0,0 @@
2002-10-25 Timothee Besset <ttimo@idsoftware.com>
If you are looking for a faster version of the q3asm tool, try:
http://www.icculus.org/~phaethon/q3/q3asm-turbo/q3asm-turbo.html
2001-10-31 Timothee Besset <ttimo@idsoftware.com>
updated from the $/source/q3asm code
modified for portability and use with >= 1.31 mod source release
the cmdlib.c cmdlib.h mathlib.h qfiles.h have been copied from
$/source/common

File diff suppressed because it is too large Load Diff

View File

@@ -1,152 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cmdlib.h
#ifndef __CMDLIB__
#define __CMDLIB__
#ifdef _MSC_VER
#pragma warning(disable : 4244) // MIPS
#pragma warning(disable : 4136) // X86
#pragma warning(disable : 4051) // ALPHA
#pragma warning(disable : 4018) // signed/unsigned mismatch
#pragma warning(disable : 4305) // truncate from double to float
#pragma check_stack(off)
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#include <stdarg.h>
#ifdef _MSC_VER
#pragma intrinsic( memset, memcpy )
#endif
#ifndef __BYTEBOOL__
#define __BYTEBOOL__
typedef enum { qfalse, qtrue } qboolean;
typedef unsigned char byte;
#endif
#define MAX_OS_PATH 1024
#define MEM_BLOCKSIZE 4096
// the dec offsetof macro doesnt work very well...
#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
// set these before calling CheckParm
extern int myargc;
extern char **myargv;
char *strupr (char *in);
char *strlower (char *in);
int Q_strncasecmp( const char *s1, const char *s2, int n );
int Q_stricmp( const char *s1, const char *s2 );
void Q_getwd( char *out );
int Q_filelength (FILE *f);
int FileTime( const char *path );
void Q_mkdir( const char *path );
extern char qdir[1024];
extern char gamedir[1024];
extern char writedir[1024];
void SetQdirFromPath( const char *path );
char *ExpandArg( const char *path ); // from cmd line
char *ExpandPath( const char *path ); // from scripts
char *ExpandGamePath (const char *path);
char *ExpandPathAndArchive( const char *path );
double I_FloatTime( void );
void Error( const char *error, ... );
int CheckParm( const char *check );
FILE *SafeOpenWrite( const char *filename );
FILE *SafeOpenRead( const char *filename );
void SafeRead (FILE *f, void *buffer, int count);
void SafeWrite (FILE *f, const void *buffer, int count);
int LoadFile( const char *filename, void **bufferptr );
int LoadFileBlock( const char *filename, void **bufferptr );
int TryLoadFile( const char *filename, void **bufferptr );
void SaveFile( const char *filename, const void *buffer, int count );
qboolean FileExists( const char *filename );
void DefaultExtension( char *path, const char *extension );
void DefaultPath( char *path, const char *basepath );
void StripFilename( char *path );
void StripExtension( char *path );
void ExtractFilePath( const char *path, char *dest );
void ExtractFileBase( const char *path, char *dest );
void ExtractFileExtension( const char *path, char *dest );
int ParseNum (const char *str);
char *COM_Parse (char *data);
extern char com_token[1024];
extern qboolean com_eof;
char *copystring(const char *s);
void CRC_Init(unsigned short *crcvalue);
void CRC_ProcessByte(unsigned short *crcvalue, byte data);
unsigned short CRC_Value(unsigned short crcvalue);
void CreatePath( const char *path );
void QCopyFile( const char *from, const char *to );
extern qboolean archive;
extern char archivedir[1024];
extern qboolean verbose;
void qprintf( const char *format, ... );
void _printf( const char *format, ... );
void ExpandWildcards( int *argc, char ***argv );
// for compression routines
typedef struct
{
void *data;
int count, width, height;
} cblock_t;
#endif

View File

@@ -1,31 +0,0 @@
strlen
strcasecmp
tolower
strcat
strncpy
strcmp
strcpy
strchr
vsprintf
memcpy
memset
rand
atoi
atof
abs
floor
fabs
tan
atan
sqrt
log
cos
sin
atan2

View File

@@ -1,94 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef __MATHLIB__
#define __MATHLIB__
// mathlib.h
#include <math.h>
#ifdef DOUBLEVEC_T
typedef double vec_t;
#else
typedef float vec_t;
#endif
typedef vec_t vec2_t[3];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
#define SIDE_FRONT 0
#define SIDE_ON 2
#define SIDE_BACK 1
#define SIDE_CROSS -2
#define Q_PI 3.14159265358979323846
#define DEG2RAD( a ) ( ( (a) * Q_PI ) / 180.0F )
#define RAD2DEG( a ) ( ( (a) * 180.0f ) / Q_PI )
extern vec3_t vec3_origin;
#define EQUAL_EPSILON 0.001
// plane types are used to speed some tests
// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2
#define PLANE_NON_AXIAL 3
qboolean VectorCompare( const vec3_t v1, const vec3_t v2 );
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];}
#define VectorClear(x) {x[0] = x[1] = x[2] = 0;}
#define VectorNegate(x) {x[0]=-x[0];x[1]=-x[1];x[2]=-x[2];}
void Vec10Copy( vec_t *in, vec_t *out );
vec_t Q_rint (vec_t in);
vec_t _DotProduct (vec3_t v1, vec3_t v2);
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out);
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out);
void _VectorCopy (vec3_t in, vec3_t out);
void _VectorScale (vec3_t v, vec_t scale, vec3_t out);
double VectorLength( const vec3_t v );
void VectorMA( const vec3_t va, double scale, const vec3_t vb, vec3_t vc );
void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross );
vec_t VectorNormalize( const vec3_t in, vec3_t out );
vec_t ColorNormalize( const vec3_t in, vec3_t out );
void VectorInverse (vec3_t v);
void ClearBounds (vec3_t mins, vec3_t maxs);
void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs );
qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c );
void NormalToLatLong( const vec3_t normal, byte bytes[2] );
int PlaneTypeForNormal (vec3_t normal);
#endif

View File

@@ -1,16 +0,0 @@
don't do any paramter conversion (double to float, etc)
Why?
Security.
Portability.
It may be more aproachable.
can still use regular dlls for development purposes
lcc
q3asm

View File

@@ -1,132 +0,0 @@
CNSTF,
CNSTI,
CNSTP,
CNSTU,
ARGB,
ARGF,
ARGI,
ARGP,
ARGU,
ASGNB,
ASGNF,
ASGNI,
ASGNP,
ASGNU,
INDIRB,
INDIRF,
INDIRI,
INDIRP,
INDIRU,
CVFF,
CVFI,
CVIF,
CVII,
CVIU,
CVPU,
CVUI,
CVUP,
CVUU,
NEGF,
NEGI,
CALLB,
CALLF,
CALLI,
CALLP,
CALLU,
CALLV,
RETF,
RETI,
RETP,
RETU,
RETV,
ADDRGP,
ADDRFP,
ADDRLP,
ADDF,
ADDI,
ADDP,
ADDU,
SUBF,
SUBI,
SUBP,
SUBU,
LSHI,
LSHU,
MODI,
MODU,
RSHI,
RSHU,
BANDI,
BANDU,
BCOMI,
BCOMU,
BORI,
BORU,
BXORI,
BXORU,
DIVF,
DIVI,
DIVU,
MULF,
MULI,
MULU,
EQF,
EQI,
EQU,
GEF,
GEI,
GEU,
GTF,
GTI,
GTU,
LEF,
LEI,
LEU,
LTF,
LTI,
LTU,
NEF,
NEI,
NEU,
JUMPV,
LABELV,
LOADB,
LOADF,
LOADI,
LOADP,
LOADU,

View File

@@ -1,175 +0,0 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
{ "BREAK", OP_BREAK },
{ "CNSTF4", OP_CONST },
{ "CNSTI4", OP_CONST },
{ "CNSTP4", OP_CONST },
{ "CNSTU4", OP_CONST },
{ "CNSTI2", OP_CONST },
{ "CNSTU2", OP_CONST },
{ "CNSTI1", OP_CONST },
{ "CNSTU1", OP_CONST },
//{ "ARGB", OP_ARG },
//{ "ARGF", OP_ARG },
//{ "ARGI", OP_ARG },
//{ "ARGP", OP_ARG },
//{ "ARGU", OP_ARG },
{ "ASGNB", OP_BLOCK_COPY },
{ "ASGNF4", OP_STORE4 },
{ "ASGNI4", OP_STORE4 },
{ "ASGNP4", OP_STORE4 },
{ "ASGNU4", OP_STORE4 },
{ "ASGNI2", OP_STORE2 },
{ "ASGNU2", OP_STORE2 },
{ "ASGNI1", OP_STORE1 },
{ "ASGNU1", OP_STORE1 },
{ "INDIRB", OP_IGNORE }, // block copy deals with this
{ "INDIRF4", OP_LOAD4 },
{ "INDIRI4", OP_LOAD4 },
{ "INDIRP4", OP_LOAD4 },
{ "INDIRU4", OP_LOAD4 },
{ "INDIRI2", OP_LOAD2 },
{ "INDIRU2", OP_LOAD2 },
{ "INDIRI1", OP_LOAD1 },
{ "INDIRU1", OP_LOAD1 },
{ "CVFF4", OP_UNDEF },
{ "CVFI4", OP_CVFI },
{ "CVIF4", OP_CVIF },
{ "CVII4", OP_SEX8 }, // will be either SEX8 or SEX16
{ "CVII1", OP_IGNORE },
{ "CVII2", OP_IGNORE },
{ "CVIU4", OP_IGNORE },
{ "CVPU4", OP_IGNORE },
{ "CVUI4", OP_IGNORE },
{ "CVUP4", OP_IGNORE },
{ "CVUU4", OP_IGNORE },
{ "CVUU1", OP_IGNORE },
{ "NEGF4", OP_NEGF },
{ "NEGI4", OP_NEGI },
//{ "CALLB", OP_UNDEF },
//{ "CALLF", OP_UNDEF },
//{ "CALLI", OP_UNDEF },
//{ "CALLP", OP_UNDEF },
//{ "CALLU", OP_UNDEF },
//{ "CALLV", OP_CALL },
//{ "RETF", OP_UNDEF },
//{ "RETI", OP_UNDEF },
//{ "RETP", OP_UNDEF },
//{ "RETU", OP_UNDEF },
//{ "RETV", OP_UNDEF },
{ "ADDRGP4", OP_CONST },
//{ "ADDRFP", OP_PARM },
//{ "ADDRLP", OP_LOCAL },
{ "ADDF4", OP_ADDF },
{ "ADDI4", OP_ADD },
{ "ADDP4", OP_ADD },
{ "ADDP", OP_ADD },
{ "ADDU4", OP_ADD },
{ "SUBF4", OP_SUBF },
{ "SUBI4", OP_SUB },
{ "SUBP4", OP_SUB },
{ "SUBU4", OP_SUB },
{ "LSHI4", OP_LSH },
{ "LSHU4", OP_LSH },
{ "MODI4", OP_MODI },
{ "MODU4", OP_MODU },
{ "RSHI4", OP_RSHI },
{ "RSHU4", OP_RSHU },
{ "BANDI4", OP_BAND },
{ "BANDU4", OP_BAND },
{ "BCOMI4", OP_BCOM },
{ "BCOMU4", OP_BCOM },
{ "BORI4", OP_BOR },
{ "BORU4", OP_BOR },
{ "BXORI4", OP_BXOR },
{ "BXORU4", OP_BXOR },
{ "DIVF4", OP_DIVF },
{ "DIVI4", OP_DIVI },
{ "DIVU4", OP_DIVU },
{ "MULF4", OP_MULF },
{ "MULI4", OP_MULI },
{ "MULU4", OP_MULU },
{ "EQF4", OP_EQF },
{ "EQI4", OP_EQ },
{ "EQU4", OP_EQ },
{ "GEF4", OP_GEF },
{ "GEI4", OP_GEI },
{ "GEU4", OP_GEU },
{ "GTF4", OP_GTF },
{ "GTI4", OP_GTI },
{ "GTU4", OP_GTU },
{ "LEF4", OP_LEF },
{ "LEI4", OP_LEI },
{ "LEU4", OP_LEU },
{ "LTF4", OP_LTF },
{ "LTI4", OP_LTI },
{ "LTU4", OP_LTU },
{ "NEF4", OP_NEF },
{ "NEI4", OP_NE },
{ "NEU4", OP_NE },
{ "JUMPV", OP_JUMP },
{ "LOADB4", OP_UNDEF },
{ "LOADF4", OP_UNDEF },
{ "LOADI4", OP_UNDEF },
{ "LOADP4", OP_UNDEF },
{ "LOADU4", OP_UNDEF },

File diff suppressed because it is too large Load Diff

View File

@@ -1,61 +0,0 @@
The authors of this software are Christopher W. Fraser and
David R. Hanson.
Copyright (c) 1991,1992,1993,1994,1995,1996,1997,1998 by AT&T,
Christopher W. Fraser, and David R. Hanson. All Rights Reserved.
Permission to use, copy, modify, and distribute this software for any
purpose, subject to the provisions described below, without fee is
hereby granted, provided that this entire notice is included in all
copies of any software that is or includes a copy or modification of
this software and in all copies of the supporting documentation for
such software.
THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
lcc is not public-domain software, shareware, and it is not protected
by a `copyleft' agreement, like the code from the Free Software
Foundation.
lcc is available free for your personal research and instructional use
under the `fair use' provisions of the copyright law. You may, however,
redistribute lcc in whole or in part provided you acknowledge its
source and include this CPYRIGHT file. You may, for example, include
the distribution in a CDROM of free software, provided you charge only
for the media, or mirror the distribution files at your site.
You may not sell lcc or any product derived from it in which it is a
significant part of the value of the product. Using the lcc front end
to build a C syntax checker is an example of this kind of product.
You may use parts of lcc in products as long as you charge for only
those components that are entirely your own and you acknowledge the use
of lcc clearly in all product documentation and distribution media. You
must state clearly that your product uses or is based on parts of lcc
and that lcc is available free of charge. You must also request that
bug reports on your product be reported to you. Using the lcc front
end to build a C compiler for the Motorola 88000 chip and charging for
and distributing only the 88000 code generator is an example of this
kind of product.
Using parts of lcc in other products is more problematic. For example,
using parts of lcc in a C++ compiler could save substantial time and
effort and therefore contribute significantly to the profitability of
the product. This kind of use, or any use where others stand to make a
profit from what is primarily our work, requires a license agreement
with Addison-Wesley. Per-copy and unlimited use licenses are
available; for more information, contact
J. Carter Shanklin
Addison Wesley Longman, Inc.
2725 Sand Hill Rd.
Menlo Park, CA 94025
650/854-0300 x2478 FAX: 650/614-2930 jcs@awl.com
-----
Chris Fraser / cwfraser@microsoft.com
David Hanson / drh@microsoft.com
$Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $

View File

@@ -1,91 +0,0 @@
From lcc 4.0 to 4.1:
Changes:
See doc/4.html for changes in the code-generation interface.
Warns about constants that are too large, eg, short x = 70000;
Warns about expressions that have no effect.
Unsigned shorts are now used for wide-character constants, and
wchar_t is a typedef for unsigned short.
More assertions in gen.c to confirm that the register allocator is
configured correctly; ie, that the various masks, wildcards,
clobbers, and targets are internally consistent. Full checking
appears impractical, but there's still more than than there was
before.
On the SPARC, lcc now emits .type and .size directives
unconditionally.
On the x86, constants are now emitted into the text segment.
If the environment variable "LCCDIR" is defined, it gives the directory
that contains the preprocessor, the compiler proper, and the
lcc-specific libraries.
Under Windows, lcc searches the directories named in the environment
variable "include" for header files.
Errors fixed:
Erroneously complained about unknown sizes for some const fields, eg,
typedef struct foo ref; struct foo { const ref *q; int a; };
f(ref *p, int i) { return p->q[i].a; }
-A -A erroneously complained about static main's that didn't conform
to the ANSI-mandated "int main(void)" or "int main(int, char **)".
Silently generated incorrect code for a structure copy with a
post-incremented target, eg,
struct { int x; } data = {1}, copy[2], *q = copy;
main() { *q++ = data; }
Generated incorrect values in some expressions with constant pointers.
Silently truncated string literals longer than 4095 characters.
Failed to emit debugging information for uninitialized globals.
Failed to diagnose missing sizes in some multi-dimensioned array
declarators, eg, extern int x[][10]; int x[5][];
Silently emitted incorrect sizes and initalizations for some
incomplete multi-dimensioned arrays involving pointers and whose size
is determined by the number of initializers.
Set only the x.name field for some back-end symbols (eg, wildcards),
and the uninitialized name field crashed some debugging output.
uses() failed to check the register *set* as well as the register
mask. There's no known bug demo, but a wildcard set might be
contrived that would need the test.
Crashed with -b on some conditional expressions involving calls, eg,
int p; void g(void) { p ? f() : 1; }
On the MIPS, sometimes generated an incorrect frame size and thus a
crash when floating-point registers were saved.
On the SPARC, erroneously reused a register variable as a temporary
when the variable is compiler-generated.
On the SPARC with -b, emitted incorrect code for returning structs.
On the x86, conversion from float to int rounded instead of truncated
with the default floating-point mode.
On the x86, eliminate rtargets for kids after the first (see p. 419).
On the x86, substitute reg for freg, in order to use the common reg
rules. Needed only for debugging output, since we're not using any
float regs as regs at this time.
On the x86, "double f(); main(){f();}" wasn't popping the FP register stack.
On the x86, ECX was saved by the callee, when it should have been
saved by the caller.
$Id: LOG 145 2001-10-17 21:53:10Z timo $

View File

@@ -1,21 +0,0 @@
This hierarchy is the distribution for lcc version 4.1.
lcc version 3.x is described in the book "A Retargetable C Compiler:
Design and Implementation" (Addison-Wesley, 1995, ISBN 0-8053-1670-1).
There are significant differences between 3.x and 4.x, most notably in
the intermediate code. doc/4.html summarizes the differences.
VERSION 4.1 IS INCOMPATIBLE WITH EARLIER VERSIONS OF LCC. DO NOT
UNLOAD THIS DISTRIBUTION ON TOP OF A 3.X DISTRIBUTION.
LOG describes the changes since the last release.
CPYRIGHT describes the conditions under you can use, copy, modify, and
distribute lcc or works derived from lcc.
doc/install.html is an HTML file that gives a complete description of
the distribution and installation instructions.
Chris Fraser / cwfraser@microsoft.com
David Hanson / drh@microsoft.com
$Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $

View File

@@ -1,3 +0,0 @@
2001-10-31 Timothee Besset <ttimo@idsoftware.com>
updated from the $/source/lcc code
modified for portability and use with >= 1.31 mod source release

View File

@@ -1,326 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include "cpp.h"
char rcsid[] = "cpp.c - faked rcsid";
#define OUTS 16384
char outbuf[OUTS];
char *outp = outbuf;
Source *cursource;
int nerrs;
struct token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" };
char *curtime;
int incdepth;
int ifdepth;
int ifsatisfied[NIF];
int skipping;
int
main(int argc, char **argv)
{
Tokenrow tr;
time_t t;
char ebuf[BUFSIZ];
setbuf(stderr, ebuf);
t = time(NULL);
curtime = ctime(&t);
maketokenrow(3, &tr);
expandlex();
setup(argc, argv);
fixlex();
iniths();
genline();
process(&tr);
flushout();
fflush(stderr);
exit(nerrs > 0);
return 0;
}
void
process(Tokenrow *trp)
{
int anymacros = 0;
for (;;) {
if (trp->tp >= trp->lp) {
trp->tp = trp->lp = trp->bp;
outp = outbuf;
anymacros |= gettokens(trp, 1);
trp->tp = trp->bp;
}
if (trp->tp->type == END) {
if (--incdepth>=0) {
if (cursource->ifdepth)
error(ERROR,
"Unterminated conditional in #include");
unsetsource();
cursource->line += cursource->lineinc;
trp->tp = trp->lp;
genline();
continue;
}
if (ifdepth)
error(ERROR, "Unterminated #if/#ifdef/#ifndef");
break;
}
if (trp->tp->type==SHARP) {
trp->tp += 1;
control(trp);
} else if (!skipping && anymacros)
expandrow(trp, NULL);
if (skipping)
setempty(trp);
puttokens(trp);
anymacros = 0;
cursource->line += cursource->lineinc;
if (cursource->lineinc>1) {
genline();
}
}
}
void
control(Tokenrow *trp)
{
Nlist *np;
Token *tp;
tp = trp->tp;
if (tp->type!=NAME) {
if (tp->type==NUMBER)
goto kline;
if (tp->type != NL)
error(ERROR, "Unidentifiable control line");
return; /* else empty line */
}
if ((np = lookup(tp, 0))==NULL || ((np->flag&ISKW)==0 && !skipping)) {
error(WARNING, "Unknown preprocessor control %t", tp);
return;
}
if (skipping) {
switch (np->val) {
case KENDIF:
if (--ifdepth<skipping)
skipping = 0;
--cursource->ifdepth;
setempty(trp);
return;
case KIFDEF:
case KIFNDEF:
case KIF:
if (++ifdepth >= NIF)
error(FATAL, "#if too deeply nested");
++cursource->ifdepth;
return;
case KELIF:
case KELSE:
if (ifdepth<=skipping)
break;
return;
default:
return;
}
}
switch (np->val) {
case KDEFINE:
dodefine(trp);
break;
case KUNDEF:
tp += 1;
if (tp->type!=NAME || trp->lp - trp->bp != 4) {
error(ERROR, "Syntax error in #undef");
break;
}
if ((np = lookup(tp, 0)) != NULL)
np->flag &= ~ISDEFINED;
break;
case KPRAGMA:
return;
case KIFDEF:
case KIFNDEF:
case KIF:
if (++ifdepth >= NIF)
error(FATAL, "#if too deeply nested");
++cursource->ifdepth;
ifsatisfied[ifdepth] = 0;
if (eval(trp, np->val))
ifsatisfied[ifdepth] = 1;
else
skipping = ifdepth;
break;
case KELIF:
if (ifdepth==0) {
error(ERROR, "#elif with no #if");
return;
}
if (ifsatisfied[ifdepth]==2)
error(ERROR, "#elif after #else");
if (eval(trp, np->val)) {
if (ifsatisfied[ifdepth])
skipping = ifdepth;
else {
skipping = 0;
ifsatisfied[ifdepth] = 1;
}
} else
skipping = ifdepth;
break;
case KELSE:
if (ifdepth==0 || cursource->ifdepth==0) {
error(ERROR, "#else with no #if");
return;
}
if (ifsatisfied[ifdepth]==2)
error(ERROR, "#else after #else");
if (trp->lp - trp->bp != 3)
error(ERROR, "Syntax error in #else");
skipping = ifsatisfied[ifdepth]? ifdepth: 0;
ifsatisfied[ifdepth] = 2;
break;
case KENDIF:
if (ifdepth==0 || cursource->ifdepth==0) {
error(ERROR, "#endif with no #if");
return;
}
--ifdepth;
--cursource->ifdepth;
if (trp->lp - trp->bp != 3)
error(WARNING, "Syntax error in #endif");
break;
case KWARNING:
trp->tp = tp+1;
error(WARNING, "#warning directive: %r", trp);
break;
case KERROR:
trp->tp = tp+1;
error(ERROR, "#error directive: %r", trp);
break;
case KLINE:
trp->tp = tp+1;
expandrow(trp, "<line>");
tp = trp->bp+2;
kline:
if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp
|| ((tp+3==trp->lp && ((tp+1)->type!=STRING))||*(tp+1)->t=='L')){
error(ERROR, "Syntax error in #line");
return;
}
cursource->line = atol((char*)tp->t)-1;
if (cursource->line<0 || cursource->line>=32768)
error(WARNING, "#line specifies number out of range");
tp = tp+1;
if (tp+1<trp->lp)
cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0);
return;
case KDEFINED:
error(ERROR, "Bad syntax for control line");
break;
case KINCLUDE:
doinclude(trp);
trp->lp = trp->bp;
return;
case KEVAL:
eval(trp, np->val);
break;
default:
error(ERROR, "Preprocessor control `%t' not yet implemented", tp);
break;
}
setempty(trp);
}
void *
domalloc(int size)
{
void *p = malloc(size);
if (p==NULL)
error(FATAL, "Out of memory from malloc");
return p;
}
void
dofree(void *p)
{
free(p);
}
void
error(enum errtype type, char *string, ...)
{
va_list ap;
char *cp, *ep;
Token *tp;
Tokenrow *trp;
Source *s;
int i;
fprintf(stderr, "cpp: ");
for (s=cursource; s; s=s->next)
if (*s->filename)
fprintf(stderr, "%s:%d ", s->filename, s->line);
va_start(ap, string);
for (ep=string; *ep; ep++) {
if (*ep=='%') {
switch (*++ep) {
case 's':
cp = va_arg(ap, char *);
fprintf(stderr, "%s", cp);
break;
case 'd':
i = va_arg(ap, int);
fprintf(stderr, "%d", i);
break;
case 't':
tp = va_arg(ap, Token *);
fprintf(stderr, "%.*s", tp->len, tp->t);
break;
case 'r':
trp = va_arg(ap, Tokenrow *);
for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) {
if (tp>trp->tp && tp->wslen)
fputc(' ', stderr);
fprintf(stderr, "%.*s", tp->len, tp->t);
}
break;
default:
fputc(*ep, stderr);
break;
}
} else
fputc(*ep, stderr);
}
va_end(ap);
fputc('\n', stderr);
if (type==FATAL)
exit(1);
if (type!=WARNING)
nerrs = 1;
fflush(stderr);
}

View File

@@ -1,166 +0,0 @@
#define INS 32768 /* input buffer */
#define OBS 4096 /* outbut buffer */
#define NARG 32 /* Max number arguments to a macro */
#define NINCLUDE 32 /* Max number of include directories (-I) */
#define NIF 32 /* depth of nesting of #if */
#ifndef EOF
#define EOF (-1)
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef __alpha
typedef unsigned char uchar;
#endif
enum toktype { END, UNCLASS, NAME, NUMBER, STRING, CCON, NL, WS, DSHARP,
EQ, NEQ, LEQ, GEQ, LSH, RSH, LAND, LOR, PPLUS, MMINUS,
ARROW, SBRA, SKET, LP, RP, DOT, AND, STAR, PLUS, MINUS,
TILDE, NOT, SLASH, PCT, LT, GT, CIRC, OR, QUEST,
COLON, ASGN, COMMA, SHARP, SEMIC, CBRA, CKET,
ASPLUS, ASMINUS, ASSTAR, ASSLASH, ASPCT, ASCIRC, ASLSH,
ASRSH, ASOR, ASAND, ELLIPS,
DSHARP1, NAME1, DEFINED, UMINUS };
enum kwtype { KIF, KIFDEF, KIFNDEF, KELIF, KELSE, KENDIF, KINCLUDE, KDEFINE,
KUNDEF, KLINE, KWARNING, KERROR, KPRAGMA, KDEFINED,
KLINENO, KFILE, KDATE, KTIME, KSTDC, KEVAL };
#define ISDEFINED 01 /* has #defined value */
#define ISKW 02 /* is PP keyword */
#define ISUNCHANGE 04 /* can't be #defined in PP */
#define ISMAC 010 /* builtin macro, e.g. __LINE__ */
#define EOB 0xFE /* sentinel for end of input buffer */
#define EOFC 0xFD /* sentinel for end of input file */
#define XPWS 1 /* token flag: white space to assure token sep. */
typedef struct token {
unsigned char type;
unsigned char flag;
unsigned short hideset;
unsigned int wslen;
unsigned int len;
uchar *t;
} Token;
typedef struct tokenrow {
Token *tp; /* current one to scan */
Token *bp; /* base (allocated value) */
Token *lp; /* last+1 token used */
int max; /* number allocated */
} Tokenrow;
typedef struct source {
char *filename; /* name of file of the source */
int line; /* current line number */
int lineinc; /* adjustment for \\n lines */
uchar *inb; /* input buffer */
uchar *inp; /* input pointer */
uchar *inl; /* end of input */
int fd; /* input source */
int ifdepth; /* conditional nesting in include */
struct source *next; /* stack for #include */
} Source;
typedef struct nlist {
struct nlist *next;
uchar *name;
int len;
Tokenrow *vp; /* value as macro */
Tokenrow *ap; /* list of argument names, if any */
char val; /* value as preprocessor name */
char flag; /* is defined, is pp name */
} Nlist;
typedef struct includelist {
char deleted;
char always;
char *file;
} Includelist;
#define new(t) (t *)domalloc(sizeof(t))
#define quicklook(a,b) (namebit[(a)&077] & (1<<((b)&037)))
#define quickset(a,b) namebit[(a)&077] |= (1<<((b)&037))
extern unsigned long namebit[077+1];
enum errtype { WARNING, ERROR, FATAL };
void expandlex(void);
void fixlex(void);
void setup(int, char **);
int gettokens(Tokenrow *, int);
int comparetokens(Tokenrow *, Tokenrow *);
Source *setsource(char *, int, char *);
void unsetsource(void);
void puttokens(Tokenrow *);
void process(Tokenrow *);
void *domalloc(int);
void dofree(void *);
void error(enum errtype, char *, ...);
void flushout(void);
int fillbuf(Source *);
int trigraph(Source *);
int foldline(Source *);
Nlist *lookup(Token *, int);
void control(Tokenrow *);
void dodefine(Tokenrow *);
void doadefine(Tokenrow *, int);
void doinclude(Tokenrow *);
void appendDirToIncludeList( char *dir );
void doif(Tokenrow *, enum kwtype);
void expand(Tokenrow *, Nlist *);
void builtin(Tokenrow *, int);
int gatherargs(Tokenrow *, Tokenrow **, int *);
void substargs(Nlist *, Tokenrow *, Tokenrow **);
void expandrow(Tokenrow *, char *);
void maketokenrow(int, Tokenrow *);
Tokenrow *copytokenrow(Tokenrow *, Tokenrow *);
Token *growtokenrow(Tokenrow *);
Tokenrow *normtokenrow(Tokenrow *);
void adjustrow(Tokenrow *, int);
void movetokenrow(Tokenrow *, Tokenrow *);
void insertrow(Tokenrow *, int, Tokenrow *);
void peektokens(Tokenrow *, char *);
void doconcat(Tokenrow *);
Tokenrow *stringify(Tokenrow *);
int lookuparg(Nlist *, Token *);
long eval(Tokenrow *, int);
void genline(void);
void setempty(Tokenrow *);
void makespace(Tokenrow *);
char *outnum(char *, int);
int digit(int);
uchar *newstring(uchar *, int, int);
int checkhideset(int, Nlist *);
void prhideset(int);
int newhideset(int, Nlist *);
int unionhideset(int, int);
void iniths(void);
void setobjname(char *);
#define rowlen(tokrow) ((tokrow)->lp - (tokrow)->bp)
char *basepath( char *fname );
extern char *outp;
extern Token nltoken;
extern Source *cursource;
extern char *curtime;
extern int incdepth;
extern int ifdepth;
extern int ifsatisfied[NIF];
extern int Mflag;
extern int skipping;
extern int verbose;
extern int Cplusplus;
extern Nlist *kwdefined;
extern Includelist includelist[NINCLUDE];
extern char wd[];
#ifndef _WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
#include <fcntl.h>

View File

@@ -1,524 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "cpp.h"
#define NSTAK 32
#define SGN 0
#define UNS 1
#define UND 2
#define UNSMARK 0x1000
struct value {
long val;
int type;
};
/* conversion types */
#define RELAT 1
#define ARITH 2
#define LOGIC 3
#define SPCL 4
#define SHIFT 5
#define UNARY 6
/* operator priority, arity, and conversion type, indexed by tokentype */
struct pri {
char pri;
char arity;
char ctype;
} priority[] = {
{ 0, 0, 0 }, /* END */
{ 0, 0, 0 }, /* UNCLASS */
{ 0, 0, 0 }, /* NAME */
{ 0, 0, 0 }, /* NUMBER */
{ 0, 0, 0 }, /* STRING */
{ 0, 0, 0 }, /* CCON */
{ 0, 0, 0 }, /* NL */
{ 0, 0, 0 }, /* WS */
{ 0, 0, 0 }, /* DSHARP */
{ 11, 2, RELAT }, /* EQ */
{ 11, 2, RELAT }, /* NEQ */
{ 12, 2, RELAT }, /* LEQ */
{ 12, 2, RELAT }, /* GEQ */
{ 13, 2, SHIFT }, /* LSH */
{ 13, 2, SHIFT }, /* RSH */
{ 7, 2, LOGIC }, /* LAND */
{ 6, 2, LOGIC }, /* LOR */
{ 0, 0, 0 }, /* PPLUS */
{ 0, 0, 0 }, /* MMINUS */
{ 0, 0, 0 }, /* ARROW */
{ 0, 0, 0 }, /* SBRA */
{ 0, 0, 0 }, /* SKET */
{ 3, 0, 0 }, /* LP */
{ 3, 0, 0 }, /* RP */
{ 0, 0, 0 }, /* DOT */
{ 10, 2, ARITH }, /* AND */
{ 15, 2, ARITH }, /* STAR */
{ 14, 2, ARITH }, /* PLUS */
{ 14, 2, ARITH }, /* MINUS */
{ 16, 1, UNARY }, /* TILDE */
{ 16, 1, UNARY }, /* NOT */
{ 15, 2, ARITH }, /* SLASH */
{ 15, 2, ARITH }, /* PCT */
{ 12, 2, RELAT }, /* LT */
{ 12, 2, RELAT }, /* GT */
{ 9, 2, ARITH }, /* CIRC */
{ 8, 2, ARITH }, /* OR */
{ 5, 2, SPCL }, /* QUEST */
{ 5, 2, SPCL }, /* COLON */
{ 0, 0, 0 }, /* ASGN */
{ 4, 2, 0 }, /* COMMA */
{ 0, 0, 0 }, /* SHARP */
{ 0, 0, 0 }, /* SEMIC */
{ 0, 0, 0 }, /* CBRA */
{ 0, 0, 0 }, /* CKET */
{ 0, 0, 0 }, /* ASPLUS */
{ 0, 0, 0 }, /* ASMINUS */
{ 0, 0, 0 }, /* ASSTAR */
{ 0, 0, 0 }, /* ASSLASH */
{ 0, 0, 0 }, /* ASPCT */
{ 0, 0, 0 }, /* ASCIRC */
{ 0, 0, 0 }, /* ASLSH */
{ 0, 0, 0 }, /* ASRSH */
{ 0, 0, 0 }, /* ASOR */
{ 0, 0, 0 }, /* ASAND */
{ 0, 0, 0 }, /* ELLIPS */
{ 0, 0, 0 }, /* DSHARP1 */
{ 0, 0, 0 }, /* NAME1 */
{ 16, 1, UNARY }, /* DEFINED */
{ 16, 0, UNARY }, /* UMINUS */
};
int evalop(struct pri);
struct value tokval(Token *);
struct value vals[NSTAK], *vp;
enum toktype ops[NSTAK], *op;
/*
* Evaluate an #if #elif #ifdef #ifndef line. trp->tp points to the keyword.
*/
long
eval(Tokenrow *trp, int kw)
{
Token *tp;
Nlist *np;
int ntok, rand;
trp->tp++;
if (kw==KIFDEF || kw==KIFNDEF) {
if (trp->lp - trp->bp != 4 || trp->tp->type!=NAME) {
error(ERROR, "Syntax error in #ifdef/#ifndef");
return 0;
}
np = lookup(trp->tp, 0);
return (kw==KIFDEF) == (np && np->flag&(ISDEFINED|ISMAC));
}
ntok = trp->tp - trp->bp;
kwdefined->val = KDEFINED; /* activate special meaning of defined */
expandrow(trp, "<if>");
kwdefined->val = NAME;
vp = vals;
op = ops;
*op++ = END;
for (rand=0, tp = trp->bp+ntok; tp < trp->lp; tp++) {
switch(tp->type) {
case WS:
case NL:
continue;
/* nilary */
case NAME:
case NAME1:
case NUMBER:
case CCON:
case STRING:
if (rand)
goto syntax;
*vp++ = tokval(tp);
rand = 1;
continue;
/* unary */
case DEFINED:
case TILDE:
case NOT:
if (rand)
goto syntax;
*op++ = tp->type;
continue;
/* unary-binary */
case PLUS: case MINUS: case STAR: case AND:
if (rand==0) {
if (tp->type==MINUS)
*op++ = UMINUS;
if (tp->type==STAR || tp->type==AND) {
error(ERROR, "Illegal operator * or & in #if/#elsif");
return 0;
}
continue;
}
/* flow through */
/* plain binary */
case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH:
case LAND: case LOR: case SLASH: case PCT:
case LT: case GT: case CIRC: case OR: case QUEST:
case COLON: case COMMA:
if (rand==0)
goto syntax;
if (evalop(priority[tp->type])!=0)
return 0;
*op++ = tp->type;
rand = 0;
continue;
case LP:
if (rand)
goto syntax;
*op++ = LP;
continue;
case RP:
if (!rand)
goto syntax;
if (evalop(priority[RP])!=0)
return 0;
if (op<=ops || op[-1]!=LP) {
goto syntax;
}
op--;
continue;
default:
error(ERROR,"Bad operator (%t) in #if/#elsif", tp);
return 0;
}
}
if (rand==0)
goto syntax;
if (evalop(priority[END])!=0)
return 0;
if (op!=&ops[1] || vp!=&vals[1]) {
error(ERROR, "Botch in #if/#elsif");
return 0;
}
if (vals[0].type==UND)
error(ERROR, "Undefined expression value");
return vals[0].val;
syntax:
error(ERROR, "Syntax error in #if/#elsif");
return 0;
}
int
evalop(struct pri pri)
{
struct value v1, v2;
long rv1, rv2;
int rtype, oper;
/* prevent compiler whining. */
v1.val = v2.val = 0;
v1.type = v2.type = 0;
rv2=0;
rtype=0;
while (pri.pri < priority[op[-1]].pri) {
oper = *--op;
if (priority[oper].arity==2) {
v2 = *--vp;
rv2 = v2.val;
}
v1 = *--vp;
rv1 = v1.val;
/*lint -e574 -e644 */
switch (priority[oper].ctype) {
case 0:
default:
error(WARNING, "Syntax error in #if/#endif");
return 1;
case ARITH:
case RELAT:
if (v1.type==UNS || v2.type==UNS)
rtype = UNS;
else
rtype = SGN;
if (v1.type==UND || v2.type==UND)
rtype = UND;
if (priority[oper].ctype==RELAT && rtype==UNS) {
oper |= UNSMARK;
rtype = SGN;
}
break;
case SHIFT:
if (v1.type==UND || v2.type==UND)
rtype = UND;
else
rtype = v1.type;
if (rtype==UNS)
oper |= UNSMARK;
break;
case UNARY:
rtype = v1.type;
break;
case LOGIC:
case SPCL:
break;
}
switch (oper) {
case EQ: case EQ|UNSMARK:
rv1 = rv1==rv2; break;
case NEQ: case NEQ|UNSMARK:
rv1 = rv1!=rv2; break;
case LEQ:
rv1 = rv1<=rv2; break;
case GEQ:
rv1 = rv1>=rv2; break;
case LT:
rv1 = rv1<rv2; break;
case GT:
rv1 = rv1>rv2; break;
case LEQ|UNSMARK:
rv1 = (unsigned long)rv1<=rv2; break;
case GEQ|UNSMARK:
rv1 = (unsigned long)rv1>=rv2; break;
case LT|UNSMARK:
rv1 = (unsigned long)rv1<rv2; break;
case GT|UNSMARK:
rv1 = (unsigned long)rv1>rv2; break;
case LSH:
rv1 <<= rv2; break;
case LSH|UNSMARK:
rv1 = (unsigned long)rv1<<rv2; break;
case RSH:
rv1 >>= rv2; break;
case RSH|UNSMARK:
rv1 = (unsigned long)rv1>>rv2; break;
case LAND:
rtype = UND;
if (v1.type==UND)
break;
if (rv1!=0) {
if (v2.type==UND)
break;
rv1 = rv2!=0;
} else
rv1 = 0;
rtype = SGN;
break;
case LOR:
rtype = UND;
if (v1.type==UND)
break;
if (rv1==0) {
if (v2.type==UND)
break;
rv1 = rv2!=0;
} else
rv1 = 1;
rtype = SGN;
break;
case AND:
rv1 &= rv2; break;
case STAR:
rv1 *= rv2; break;
case PLUS:
rv1 += rv2; break;
case MINUS:
rv1 -= rv2; break;
case UMINUS:
if (v1.type==UND)
rtype = UND;
rv1 = -rv1; break;
case OR:
rv1 |= rv2; break;
case CIRC:
rv1 ^= rv2; break;
case TILDE:
rv1 = ~rv1; break;
case NOT:
rv1 = !rv1; if (rtype!=UND) rtype = SGN; break;
case SLASH:
if (rv2==0) {
rtype = UND;
break;
}
if (rtype==UNS)
rv1 /= (unsigned long)rv2;
else
rv1 /= rv2;
break;
case PCT:
if (rv2==0) {
rtype = UND;
break;
}
if (rtype==UNS)
rv1 %= (unsigned long)rv2;
else
rv1 %= rv2;
break;
case COLON:
if (op[-1] != QUEST)
error(ERROR, "Bad ?: in #if/endif");
else {
op--;
if ((--vp)->val==0)
v1 = v2;
rtype = v1.type;
rv1 = v1.val;
}
break;
case DEFINED:
break;
default:
error(ERROR, "Eval botch (unknown operator)");
return 1;
}
/*lint +e574 +e644 */
v1.val = rv1;
v1.type = rtype;
*vp++ = v1;
}
return 0;
}
struct value
tokval(Token *tp)
{
struct value v;
Nlist *np;
int i, base, c;
unsigned long n;
uchar *p;
v.type = SGN;
v.val = 0;
switch (tp->type) {
case NAME:
v.val = 0;
break;
case NAME1:
if ((np = lookup(tp, 0)) != NULL && np->flag&(ISDEFINED|ISMAC))
v.val = 1;
break;
case NUMBER:
n = 0;
base = 10;
p = tp->t;
c = p[tp->len];
p[tp->len] = '\0';
if (*p=='0') {
base = 8;
if (p[1]=='x' || p[1]=='X') {
base = 16;
p++;
}
p++;
}
for (;; p++) {
if ((i = digit(*p)) < 0)
break;
if (i>=base)
error(WARNING,
"Bad digit in number %t", tp);
n *= base;
n += i;
}
if (n>=0x80000000 && base!=10)
v.type = UNS;
for (; *p; p++) {
if (*p=='u' || *p=='U')
v.type = UNS;
else if (*p=='l' || *p=='L')
;
else {
error(ERROR,
"Bad number %t in #if/#elsif", tp);
break;
}
}
v.val = n;
tp->t[tp->len] = c;
break;
case CCON:
n = 0;
p = tp->t;
if (*p=='L') {
p += 1;
error(WARNING, "Wide char constant value undefined");
}
p += 1;
if (*p=='\\') {
p += 1;
if ((i = digit(*p))>=0 && i<=7) {
n = i;
p += 1;
if ((i = digit(*p))>=0 && i<=7) {
p += 1;
n <<= 3;
n += i;
if ((i = digit(*p))>=0 && i<=7) {
p += 1;
n <<= 3;
n += i;
}
}
} else if (*p=='x') {
p += 1;
while ((i = digit(*p))>=0 && i<=15) {
p += 1;
n <<= 4;
n += i;
}
} else {
static char cvcon[]
= "b\bf\fn\nr\rt\tv\v''\"\"??\\\\";
for (i=0; i<sizeof(cvcon); i+=2) {
if (*p == cvcon[i]) {
n = cvcon[i+1];
break;
}
}
p += 1;
if (i>=sizeof(cvcon))
error(WARNING,
"Undefined escape in character constant");
}
} else if (*p=='\'')
error(ERROR, "Empty character constant");
else
n = *p++;
if (*p!='\'')
error(WARNING, "Multibyte character constant undefined");
else if (n>127)
error(WARNING, "Character constant taken as not signed");
v.val = n;
break;
case STRING:
error(ERROR, "String in #if/#elsif");
break;
}
return v;
}
int
digit(int i)
{
if ('0'<=i && i<='9')
i -= '0';
else if ('a'<=i && i<='f')
i -= 'a'-10;
else if ('A'<=i && i<='F')
i -= 'A'-10;
else
i = -1;
return i;
}

View File

@@ -1,53 +0,0 @@
#include <stdio.h>
#include <string.h>
#define EPR fprintf(stderr,
#define ERR(str, chr) if(opterr){EPR "%s%c\n", str, chr);}
int opterr = 1;
int optind = 1;
int optopt;
char *optarg;
int
lcc_getopt (int argc, char *const argv[], const char *opts)
{
static int sp = 1;
int c;
char *cp;
if (sp == 1) {
if (optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0')
return -1;
else if (strcmp(argv[optind], "--") == 0) {
optind++;
return -1;
}
}
optopt = c = argv[optind][sp];
if (c == ':' || (cp=strchr(opts, c)) == 0) {
ERR (": illegal option -- ", c);
if (argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return '?';
}
if (*++cp == ':') {
if (argv[optind][sp+1] != '\0')
optarg = &argv[optind++][sp+1];
else if (++optind >= argc) {
ERR (": option requires an argument -- ", c);
sp = 1;
return '?';
} else
optarg = argv[optind++];
sp = 1;
} else {
if (argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = 0;
}
return c;
}

View File

@@ -1,112 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpp.h"
/*
* A hideset is a null-terminated array of Nlist pointers.
* They are referred to by indices in the hidesets array.
* Hideset 0 is empty.
*/
#define HSSIZ 32
typedef Nlist **Hideset;
Hideset *hidesets;
int nhidesets = 0;
int maxhidesets = 3;
int inserths(Hideset, Hideset, Nlist *);
/*
* Test for membership in a hideset
*/
int
checkhideset(int hs, Nlist *np)
{
Hideset hsp;
if (hs>=nhidesets)
abort();
for (hsp = hidesets[hs]; *hsp; hsp++) {
if (*hsp == np)
return 1;
}
return 0;
}
/*
* Return the (possibly new) hideset obtained by adding np to hs.
*/
int
newhideset(int hs, Nlist *np)
{
int i, len;
Nlist *nhs[HSSIZ+3];
Hideset hs1, hs2;
len = inserths(nhs, hidesets[hs], np);
for (i=0; i<nhidesets; i++) {
for (hs1=nhs, hs2=hidesets[i]; *hs1==*hs2; hs1++, hs2++)
if (*hs1 == NULL)
return i;
}
if (len>=HSSIZ)
return hs;
if (nhidesets >= maxhidesets) {
maxhidesets = 3*maxhidesets/2+1;
hidesets = (Hideset *)realloc(hidesets, (sizeof (Hideset *))*maxhidesets);
if (hidesets == NULL)
error(FATAL, "Out of memory from realloc");
}
hs1 = (Hideset)domalloc(len*sizeof(Hideset));
memmove(hs1, nhs, len*sizeof(Hideset));
hidesets[nhidesets] = hs1;
return nhidesets++;
}
int
inserths(Hideset dhs, Hideset shs, Nlist *np)
{
Hideset odhs = dhs;
while (*shs && *shs < np)
*dhs++ = *shs++;
if (*shs != np)
*dhs++ = np;
do {
*dhs++ = *shs;
} while (*shs++);
return dhs - odhs;
}
/*
* Hideset union
*/
int
unionhideset(int hs1, int hs2)
{
Hideset hp;
for (hp = hidesets[hs2]; *hp; hp++)
hs1 = newhideset(hs1, *hp);
return hs1;
}
void
iniths(void)
{
hidesets = (Hideset *)domalloc(maxhidesets*sizeof(Hideset *));
hidesets[0] = (Hideset)domalloc(sizeof(Hideset));
*hidesets[0] = NULL;
nhidesets++;
}
void
prhideset(int hs)
{
Hideset np;
for (np = hidesets[hs]; *np; np++) {
fprintf(stderr, (char*)(*np)->name, (*np)->len);
fprintf(stderr, " ");
}
}

View File

@@ -1,153 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpp.h"
Includelist includelist[NINCLUDE];
extern char *objname;
void appendDirToIncludeList( char *dir )
{
int i;
char *fqdir;
fqdir = (char *)newstring( (uchar *)includelist[NINCLUDE-1].file, 256, 0 );
strcat( fqdir, "/" );
strcat( fqdir, dir );
//avoid adding it more than once
for (i=NINCLUDE-2; i>=0; i--) {
if (includelist[i].file &&
!strcmp (includelist[i].file, fqdir)) {
return;
}
}
for (i=NINCLUDE-2; i>=0; i--) {
if (includelist[i].file==NULL) {
includelist[i].always = 1;
includelist[i].file = fqdir;
break;
}
}
if (i<0)
error(FATAL, "Too many -I directives");
}
void
doinclude(Tokenrow *trp)
{
char fname[256], iname[256];
Includelist *ip;
int angled, len, fd, i;
trp->tp += 1;
if (trp->tp>=trp->lp)
goto syntax;
if (trp->tp->type!=STRING && trp->tp->type!=LT) {
len = trp->tp - trp->bp;
expandrow(trp, "<include>");
trp->tp = trp->bp+len;
}
if (trp->tp->type==STRING) {
len = trp->tp->len-2;
if (len > sizeof(fname) - 1)
len = sizeof(fname) - 1;
strncpy(fname, (char*)trp->tp->t+1, len);
angled = 0;
} else if (trp->tp->type==LT) {
len = 0;
trp->tp++;
while (trp->tp->type!=GT) {
if (trp->tp>trp->lp || len+trp->tp->len+2 >= sizeof(fname))
goto syntax;
strncpy(fname+len, (char*)trp->tp->t, trp->tp->len);
len += trp->tp->len;
trp->tp++;
}
angled = 1;
} else
goto syntax;
trp->tp += 2;
if (trp->tp < trp->lp || len==0)
goto syntax;
fname[len] = '\0';
appendDirToIncludeList( basepath( fname ) );
if (fname[0]=='/') {
fd = open(fname, 0);
strcpy(iname, fname);
} else for (fd = -1,i=NINCLUDE-1; i>=0; i--) {
ip = &includelist[i];
if (ip->file==NULL || ip->deleted || (angled && ip->always==0))
continue;
if (strlen(fname)+strlen(ip->file)+2 > sizeof(iname))
continue;
strcpy(iname, ip->file);
strcat(iname, "/");
strcat(iname, fname);
if ((fd = open(iname, 0)) >= 0)
break;
}
if ( Mflag>1 || (!angled&&Mflag==1) ) {
write(1,objname,strlen(objname));
write(1,iname,strlen(iname));
write(1,"\n",1);
}
if (fd >= 0) {
if (++incdepth > 10)
error(FATAL, "#include too deeply nested");
setsource((char*)newstring((uchar*)iname, strlen(iname), 0), fd, NULL);
genline();
} else {
trp->tp = trp->bp+2;
error(ERROR, "Could not find include file %r", trp);
}
return;
syntax:
error(ERROR, "Syntax error in #include");
}
/*
* Generate a line directive for cursource
*/
void
genline(void)
{
static Token ta = { UNCLASS };
static Tokenrow tr = { &ta, &ta, &ta+1, 1 };
uchar *p;
ta.t = p = (uchar*)outp;
strcpy((char*)p, "#line ");
p += sizeof("#line ")-1;
p = (uchar*)outnum((char*)p, cursource->line);
*p++ = ' '; *p++ = '"';
if (cursource->filename[0]!='/' && wd[0]) {
strcpy((char*)p, wd);
p += strlen(wd);
*p++ = '/';
}
strcpy((char*)p, cursource->filename);
p += strlen((char*)p);
*p++ = '"'; *p++ = '\n';
ta.len = (char*)p-outp;
outp = (char*)p;
tr.tp = tr.bp;
puttokens(&tr);
}
void
setobjname(char *f)
{
int n = strlen(f);
objname = (char*)domalloc(n+5);
strcpy(objname,f);
if(objname[n-2]=='.'){
strcpy(objname+n-1,"$O: ");
}else{
strcpy(objname+n,"$O: ");
}
}

View File

@@ -1,580 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpp.h"
/*
* lexical FSM encoding
* when in state state, and one of the characters
* in ch arrives, enter nextstate.
* States >= S_SELF are either final, or at least require special action.
* In 'fsm' there is a line for each state X charset X nextstate.
* List chars that overwrite previous entries later (e.g. C_ALPH
* can be overridden by '_' by a later entry; and C_XX is the
* the universal set, and should always be first.
* States above S_SELF are represented in the big table as negative values.
* S_SELF and S_SELFB encode the resulting token type in the upper bits.
* These actions differ in that S_SELF doesn't have a lookahead char,
* S_SELFB does.
*
* The encoding is blown out into a big table for time-efficiency.
* Entries have
* nextstate: 6 bits; ?\ marker: 1 bit; tokentype: 9 bits.
*/
#define MAXSTATE 32
#define ACT(tok,act) ((tok<<7)+act)
#define QBSBIT 0100
#define GETACT(st) (st>>7)&0x1ff
/* character classes */
#define C_WS 1
#define C_ALPH 2
#define C_NUM 3
#define C_EOF 4
#define C_XX 5
enum state {
START=0, NUM1, NUM2, NUM3, ID1, ST1, ST2, ST3, COM1, COM2, COM3, COM4,
CC1, CC2, WS1, PLUS1, MINUS1, STAR1, SLASH1, PCT1, SHARP1,
CIRC1, GT1, GT2, LT1, LT2, OR1, AND1, ASG1, NOT1, DOTS1,
S_SELF=MAXSTATE, S_SELFB, S_EOF, S_NL, S_EOFSTR,
S_STNL, S_COMNL, S_EOFCOM, S_COMMENT, S_EOB, S_WS, S_NAME
};
int tottok;
int tokkind[256];
struct fsm {
int state; /* if in this state */
uchar ch[4]; /* and see one of these characters */
int nextstate; /* enter this state if +ve */
};
/*const*/ struct fsm fsm[] = {
/* start state */
{START, { C_XX }, ACT(UNCLASS,S_SELF)},
{START, { ' ', '\t', '\v' }, WS1},
{START, { C_NUM }, NUM1},
{START, { '.' }, NUM3},
{START, { C_ALPH }, ID1},
{START, { 'L' }, ST1},
{START, { '"' }, ST2},
{START, { '\'' }, CC1},
{START, { '/' }, COM1},
{START, { EOFC }, S_EOF},
{START, { '\n' }, S_NL},
{START, { '-' }, MINUS1},
{START, { '+' }, PLUS1},
{START, { '<' }, LT1},
{START, { '>' }, GT1},
{START, { '=' }, ASG1},
{START, { '!' }, NOT1},
{START, { '&' }, AND1},
{START, { '|' }, OR1},
{START, { '#' }, SHARP1},
{START, { '%' }, PCT1},
{START, { '[' }, ACT(SBRA,S_SELF)},
{START, { ']' }, ACT(SKET,S_SELF)},
{START, { '(' }, ACT(LP,S_SELF)},
{START, { ')' }, ACT(RP,S_SELF)},
{START, { '*' }, STAR1},
{START, { ',' }, ACT(COMMA,S_SELF)},
{START, { '?' }, ACT(QUEST,S_SELF)},
{START, { ':' }, ACT(COLON,S_SELF)},
{START, { ';' }, ACT(SEMIC,S_SELF)},
{START, { '{' }, ACT(CBRA,S_SELF)},
{START, { '}' }, ACT(CKET,S_SELF)},
{START, { '~' }, ACT(TILDE,S_SELF)},
{START, { '^' }, CIRC1},
/* saw a digit */
{NUM1, { C_XX }, ACT(NUMBER,S_SELFB)},
{NUM1, { C_NUM, C_ALPH, '.' }, NUM1},
{NUM1, { 'E', 'e' }, NUM2},
{NUM1, { '_' }, ACT(NUMBER,S_SELFB)},
/* saw possible start of exponent, digits-e */
{NUM2, { C_XX }, ACT(NUMBER,S_SELFB)},
{NUM2, { '+', '-' }, NUM1},
{NUM2, { C_NUM, C_ALPH }, NUM1},
{NUM2, { '_' }, ACT(NUMBER,S_SELFB)},
/* saw a '.', which could be a number or an operator */
{NUM3, { C_XX }, ACT(DOT,S_SELFB)},
{NUM3, { '.' }, DOTS1},
{NUM3, { C_NUM }, NUM1},
{DOTS1, { C_XX }, ACT(UNCLASS, S_SELFB)},
{DOTS1, { C_NUM }, NUM1},
{DOTS1, { '.' }, ACT(ELLIPS, S_SELF)},
/* saw a letter or _ */
{ID1, { C_XX }, ACT(NAME,S_NAME)},
{ID1, { C_ALPH, C_NUM }, ID1},
/* saw L (start of wide string?) */
{ST1, { C_XX }, ACT(NAME,S_NAME)},
{ST1, { C_ALPH, C_NUM }, ID1},
{ST1, { '"' }, ST2},
{ST1, { '\'' }, CC1},
/* saw " beginning string */
{ST2, { C_XX }, ST2},
{ST2, { '"' }, ACT(STRING, S_SELF)},
{ST2, { '\\' }, ST3},
{ST2, { '\n' }, S_STNL},
{ST2, { EOFC }, S_EOFSTR},
/* saw \ in string */
{ST3, { C_XX }, ST2},
{ST3, { '\n' }, S_STNL},
{ST3, { EOFC }, S_EOFSTR},
/* saw ' beginning character const */
{CC1, { C_XX }, CC1},
{CC1, { '\'' }, ACT(CCON, S_SELF)},
{CC1, { '\\' }, CC2},
{CC1, { '\n' }, S_STNL},
{CC1, { EOFC }, S_EOFSTR},
/* saw \ in ccon */
{CC2, { C_XX }, CC1},
{CC2, { '\n' }, S_STNL},
{CC2, { EOFC }, S_EOFSTR},
/* saw /, perhaps start of comment */
{COM1, { C_XX }, ACT(SLASH, S_SELFB)},
{COM1, { '=' }, ACT(ASSLASH, S_SELF)},
{COM1, { '*' }, COM2},
{COM1, { '/' }, COM4},
/* saw / then *, start of comment */
{COM2, { C_XX }, COM2},
{COM2, { '\n' }, S_COMNL},
{COM2, { '*' }, COM3},
{COM2, { EOFC }, S_EOFCOM},
/* saw the * possibly ending a comment */
{COM3, { C_XX }, COM2},
{COM3, { '\n' }, S_COMNL},
{COM3, { '*' }, COM3},
{COM3, { '/' }, S_COMMENT},
/* // comment */
{COM4, { C_XX }, COM4},
{COM4, { '\n' }, S_NL},
{COM4, { EOFC }, S_EOFCOM},
/* saw white space, eat it up */
{WS1, { C_XX }, S_WS},
{WS1, { ' ', '\t', '\v' }, WS1},
/* saw -, check --, -=, -> */
{MINUS1, { C_XX }, ACT(MINUS, S_SELFB)},
{MINUS1, { '-' }, ACT(MMINUS, S_SELF)},
{MINUS1, { '=' }, ACT(ASMINUS,S_SELF)},
{MINUS1, { '>' }, ACT(ARROW,S_SELF)},
/* saw +, check ++, += */
{PLUS1, { C_XX }, ACT(PLUS, S_SELFB)},
{PLUS1, { '+' }, ACT(PPLUS, S_SELF)},
{PLUS1, { '=' }, ACT(ASPLUS, S_SELF)},
/* saw <, check <<, <<=, <= */
{LT1, { C_XX }, ACT(LT, S_SELFB)},
{LT1, { '<' }, LT2},
{LT1, { '=' }, ACT(LEQ, S_SELF)},
{LT2, { C_XX }, ACT(LSH, S_SELFB)},
{LT2, { '=' }, ACT(ASLSH, S_SELF)},
/* saw >, check >>, >>=, >= */
{GT1, { C_XX }, ACT(GT, S_SELFB)},
{GT1, { '>' }, GT2},
{GT1, { '=' }, ACT(GEQ, S_SELF)},
{GT2, { C_XX }, ACT(RSH, S_SELFB)},
{GT2, { '=' }, ACT(ASRSH, S_SELF)},
/* = */
{ASG1, { C_XX }, ACT(ASGN, S_SELFB)},
{ASG1, { '=' }, ACT(EQ, S_SELF)},
/* ! */
{NOT1, { C_XX }, ACT(NOT, S_SELFB)},
{NOT1, { '=' }, ACT(NEQ, S_SELF)},
/* & */
{AND1, { C_XX }, ACT(AND, S_SELFB)},
{AND1, { '&' }, ACT(LAND, S_SELF)},
{AND1, { '=' }, ACT(ASAND, S_SELF)},
/* | */
{OR1, { C_XX }, ACT(OR, S_SELFB)},
{OR1, { '|' }, ACT(LOR, S_SELF)},
{OR1, { '=' }, ACT(ASOR, S_SELF)},
/* # */
{SHARP1, { C_XX }, ACT(SHARP, S_SELFB)},
{SHARP1, { '#' }, ACT(DSHARP, S_SELF)},
/* % */
{PCT1, { C_XX }, ACT(PCT, S_SELFB)},
{PCT1, { '=' }, ACT(ASPCT, S_SELF)},
/* * */
{STAR1, { C_XX }, ACT(STAR, S_SELFB)},
{STAR1, { '=' }, ACT(ASSTAR, S_SELF)},
/* ^ */
{CIRC1, { C_XX }, ACT(CIRC, S_SELFB)},
{CIRC1, { '=' }, ACT(ASCIRC, S_SELF)},
{-1}
};
/* first index is char, second is state */
/* increase #states to power of 2 to encourage use of shift */
short bigfsm[256][MAXSTATE];
void
expandlex(void)
{
/*const*/ struct fsm *fp;
int i, j, nstate;
for (fp = fsm; fp->state>=0; fp++) {
for (i=0; fp->ch[i]; i++) {
nstate = fp->nextstate;
if (nstate >= S_SELF)
nstate = ~nstate;
switch (fp->ch[i]) {
case C_XX: /* random characters */
for (j=0; j<256; j++)
bigfsm[j][fp->state] = nstate;
continue;
case C_ALPH:
for (j=0; j<=256; j++)
if (('a'<=j&&j<='z') || ('A'<=j&&j<='Z')
|| j=='_')
bigfsm[j][fp->state] = nstate;
continue;
case C_NUM:
for (j='0'; j<='9'; j++)
bigfsm[j][fp->state] = nstate;
continue;
default:
bigfsm[fp->ch[i]][fp->state] = nstate;
}
}
}
/* install special cases for ? (trigraphs), \ (splicing), runes, and EOB */
for (i=0; i<MAXSTATE; i++) {
for (j=0; j<0xFF; j++)
if (j=='?' || j=='\\') {
if (bigfsm[j][i]>0)
bigfsm[j][i] = ~bigfsm[j][i];
bigfsm[j][i] &= ~QBSBIT;
}
bigfsm[EOB][i] = ~S_EOB;
if (bigfsm[EOFC][i]>=0)
bigfsm[EOFC][i] = ~S_EOF;
}
}
void
fixlex(void)
{
/* do C++ comments? */
if (Cplusplus==0)
bigfsm['/'][COM1] = bigfsm['x'][COM1];
}
/*
* fill in a row of tokens from input, terminated by NL or END
* First token is put at trp->lp.
* Reset is non-zero when the input buffer can be "rewound."
* The value is a flag indicating that possible macros have
* been seen in the row.
*/
int
gettokens(Tokenrow *trp, int reset)
{
register int c, state, oldstate;
register uchar *ip;
register Token *tp, *maxp;
int runelen;
Source *s = cursource;
int nmac = 0;
tp = trp->lp;
ip = s->inp;
if (reset) {
s->lineinc = 0;
if (ip>=s->inl) { /* nothing in buffer */
s->inl = s->inb;
fillbuf(s);
ip = s->inp = s->inb;
} else if (ip >= s->inb+(3*INS/4)) {
memmove(s->inb, ip, 4+s->inl-ip);
s->inl = s->inb+(s->inl-ip);
ip = s->inp = s->inb;
}
}
maxp = &trp->bp[trp->max];
runelen = 1;
for (;;) {
continue2:
if (tp>=maxp) {
trp->lp = tp;
tp = growtokenrow(trp);
maxp = &trp->bp[trp->max];
}
tp->type = UNCLASS;
tp->hideset = 0;
tp->t = ip;
tp->wslen = 0;
tp->flag = 0;
state = START;
for (;;) {
oldstate = state;
c = *ip;
if ((state = bigfsm[c][state]) >= 0) {
ip += runelen;
runelen = 1;
continue;
}
state = ~state;
reswitch:
switch (state&0177) {
case S_SELF:
ip += runelen;
runelen = 1;
case S_SELFB:
tp->type = GETACT(state);
tp->len = ip - tp->t;
tp++;
goto continue2;
case S_NAME: /* like S_SELFB but with nmac check */
tp->type = NAME;
tp->len = ip - tp->t;
nmac |= quicklook(tp->t[0], tp->len>1?tp->t[1]:0);
tp++;
goto continue2;
case S_WS:
tp->wslen = ip - tp->t;
tp->t = ip;
state = START;
continue;
default:
if ((state&QBSBIT)==0) {
ip += runelen;
runelen = 1;
continue;
}
state &= ~QBSBIT;
s->inp = ip;
if (c=='?') { /* check trigraph */
if (trigraph(s)) {
state = oldstate;
continue;
}
goto reswitch;
}
if (c=='\\') { /* line-folding */
if (foldline(s)) {
s->lineinc++;
state = oldstate;
continue;
}
goto reswitch;
}
error(WARNING, "Lexical botch in cpp");
ip += runelen;
runelen = 1;
continue;
case S_EOB:
s->inp = ip;
fillbuf(cursource);
state = oldstate;
continue;
case S_EOF:
tp->type = END;
tp->len = 0;
s->inp = ip;
if (tp!=trp->bp && (tp-1)->type!=NL && cursource->fd!=-1)
error(WARNING,"No newline at end of file");
trp->lp = tp+1;
return nmac;
case S_STNL:
error(ERROR, "Unterminated string or char const");
case S_NL:
tp->t = ip;
tp->type = NL;
tp->len = 1;
tp->wslen = 0;
s->lineinc++;
s->inp = ip+1;
trp->lp = tp+1;
return nmac;
case S_EOFSTR:
error(FATAL, "EOF in string or char constant");
break;
case S_COMNL:
s->lineinc++;
state = COM2;
ip += runelen;
runelen = 1;
if (ip >= s->inb+(7*INS/8)) { /* very long comment */
memmove(tp->t, ip, 4+s->inl-ip);
s->inl -= ip-tp->t;
ip = tp->t+1;
}
continue;
case S_EOFCOM:
error(WARNING, "EOF inside comment");
--ip;
case S_COMMENT:
++ip;
tp->t = ip;
tp->t[-1] = ' ';
tp->wslen = 1;
state = START;
continue;
}
break;
}
ip += runelen;
runelen = 1;
tp->len = ip - tp->t;
tp++;
}
}
/* have seen ?; handle the trigraph it starts (if any) else 0 */
int
trigraph(Source *s)
{
int c;
while (s->inp+2 >= s->inl && fillbuf(s)!=EOF)
;
if (s->inp[1]!='?')
return 0;
c = 0;
switch(s->inp[2]) {
case '=':
c = '#'; break;
case '(':
c = '['; break;
case '/':
c = '\\'; break;
case ')':
c = ']'; break;
case '\'':
c = '^'; break;
case '<':
c = '{'; break;
case '!':
c = '|'; break;
case '>':
c = '}'; break;
case '-':
c = '~'; break;
}
if (c) {
*s->inp = c;
memmove(s->inp+1, s->inp+3, s->inl-s->inp+2);
s->inl -= 2;
}
return c;
}
int
foldline(Source *s)
{
while (s->inp+1 >= s->inl && fillbuf(s)!=EOF)
;
if (s->inp[1] == '\n') {
memmove(s->inp, s->inp+2, s->inl-s->inp+3);
s->inl -= 2;
return 1;
}
return 0;
}
int
fillbuf(Source *s)
{
int n, nr;
nr = INS/8;
if ((char *)s->inl+nr > (char *)s->inb+INS)
error(FATAL, "Input buffer overflow");
if (s->fd<0 || (n=read(s->fd, (char *)s->inl, INS/8)) <= 0)
n = 0;
if ((*s->inp&0xff) == EOB) /* sentinel character appears in input */
*s->inp = EOFC;
s->inl += n;
s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOB;
if (n==0) {
s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOFC;
return EOF;
}
return 0;
}
/*
* Push down to new source of characters.
* If fd>0 and str==NULL, then from a file `name';
* if fd==-1 and str, then from the string.
*/
Source *
setsource(char *name, int fd, char *str)
{
Source *s = new(Source);
int len;
s->line = 1;
s->lineinc = 0;
s->fd = fd;
s->filename = name;
s->next = cursource;
s->ifdepth = 0;
cursource = s;
/* slop at right for EOB */
if (str) {
len = strlen(str);
s->inb = domalloc(len+4);
s->inp = s->inb;
strncpy((char *)s->inp, str, len);
} else {
s->inb = domalloc(INS+4);
s->inp = s->inb;
len = 0;
}
s->inl = s->inp+len;
s->inl[0] = s->inl[1] = EOB;
return s;
}
void
unsetsource(void)
{
Source *s = cursource;
if (s->fd>=0) {
close(s->fd);
dofree(s->inb);
}
cursource = s->next;
dofree(s);
}

View File

@@ -1,514 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpp.h"
/*
* do a macro definition. tp points to the name being defined in the line
*/
void
dodefine(Tokenrow *trp)
{
Token *tp;
Nlist *np;
Tokenrow *def, *args;
tp = trp->tp+1;
if (tp>=trp->lp || tp->type!=NAME) {
error(ERROR, "#defined token is not a name");
return;
}
np = lookup(tp, 1);
if (np->flag&ISUNCHANGE) {
error(ERROR, "#defined token %t can't be redefined", tp);
return;
}
/* collect arguments */
tp += 1;
args = NULL;
if (tp<trp->lp && tp->type==LP && tp->wslen==0) {
/* macro with args */
int narg = 0;
tp += 1;
args = new(Tokenrow);
maketokenrow(2, args);
if (tp->type!=RP) {
int err = 0;
for (;;) {
Token *atp;
if (tp->type!=NAME) {
err++;
break;
}
if (narg>=args->max)
growtokenrow(args);
for (atp=args->bp; atp<args->lp; atp++)
if (atp->len==tp->len
&& strncmp((char*)atp->t, (char*)tp->t, tp->len)==0)
error(ERROR, "Duplicate macro argument");
*args->lp++ = *tp;
narg++;
tp += 1;
if (tp->type==RP)
break;
if (tp->type!=COMMA) {
err++;
break;
}
tp += 1;
}
if (err) {
error(ERROR, "Syntax error in macro parameters");
return;
}
}
tp += 1;
}
trp->tp = tp;
if (((trp->lp)-1)->type==NL)
trp->lp -= 1;
def = normtokenrow(trp);
if (np->flag&ISDEFINED) {
if (comparetokens(def, np->vp)
|| (np->ap==NULL) != (args==NULL)
|| (np->ap && comparetokens(args, np->ap)))
error(ERROR, "Macro redefinition of %t", trp->bp+2);
}
if (args) {
Tokenrow *tap;
tap = normtokenrow(args);
dofree(args->bp);
args = tap;
}
np->ap = args;
np->vp = def;
np->flag |= ISDEFINED;
}
/*
* Definition received via -D or -U
*/
void
doadefine(Tokenrow *trp, int type)
{
Nlist *np;
static Token onetoken[1] = {{ NUMBER, 0, 0, 0, 1, (uchar*)"1" }};
static Tokenrow onetr = { onetoken, onetoken, onetoken+1, 1 };
trp->tp = trp->bp;
if (type=='U') {
if (trp->lp-trp->tp != 2 || trp->tp->type!=NAME)
goto syntax;
if ((np = lookup(trp->tp, 0)) == NULL)
return;
np->flag &= ~ISDEFINED;
return;
}
if (trp->tp >= trp->lp || trp->tp->type!=NAME)
goto syntax;
np = lookup(trp->tp, 1);
np->flag |= ISDEFINED;
trp->tp += 1;
if (trp->tp >= trp->lp || trp->tp->type==END) {
np->vp = &onetr;
return;
}
if (trp->tp->type!=ASGN)
goto syntax;
trp->tp += 1;
if ((trp->lp-1)->type == END)
trp->lp -= 1;
np->vp = normtokenrow(trp);
return;
syntax:
error(FATAL, "Illegal -D or -U argument %r", trp);
}
/*
* Do macro expansion in a row of tokens.
* Flag is NULL if more input can be gathered.
*/
void
expandrow(Tokenrow *trp, char *flag)
{
Token *tp;
Nlist *np;
if (flag)
setsource(flag, -1, "");
for (tp = trp->tp; tp<trp->lp; ) {
if (tp->type!=NAME
|| quicklook(tp->t[0], tp->len>1?tp->t[1]:0)==0
|| (np = lookup(tp, 0))==NULL
|| (np->flag&(ISDEFINED|ISMAC))==0
|| (tp->hideset && checkhideset(tp->hideset, np))) {
tp++;
continue;
}
trp->tp = tp;
if (np->val==KDEFINED) {
tp->type = DEFINED;
if ((tp+1)<trp->lp && (tp+1)->type==NAME)
(tp+1)->type = NAME1;
else if ((tp+3)<trp->lp && (tp+1)->type==LP
&& (tp+2)->type==NAME && (tp+3)->type==RP)
(tp+2)->type = NAME1;
else
error(ERROR, "Incorrect syntax for `defined'");
tp++;
continue;
}
if (np->flag&ISMAC)
builtin(trp, np->val);
else {
expand(trp, np);
}
tp = trp->tp;
}
if (flag)
unsetsource();
}
/*
* Expand the macro whose name is np, at token trp->tp, in the tokenrow.
* Return trp->tp at the first token next to be expanded
* (ordinarily the beginning of the expansion)
*/
void
expand(Tokenrow *trp, Nlist *np)
{
Tokenrow ntr;
int ntokc, narg, i;
Token *tp;
Tokenrow *atr[NARG+1];
int hs;
copytokenrow(&ntr, np->vp); /* copy macro value */
if (np->ap==NULL) /* parameterless */
ntokc = 1;
else {
ntokc = gatherargs(trp, atr, &narg);
if (narg<0) { /* not actually a call (no '(') */
trp->tp++;
return;
}
if (narg != rowlen(np->ap)) {
error(ERROR, "Disagreement in number of macro arguments");
trp->tp->hideset = newhideset(trp->tp->hideset, np);
trp->tp += ntokc;
return;
}
substargs(np, &ntr, atr); /* put args into replacement */
for (i=0; i<narg; i++) {
dofree(atr[i]->bp);
dofree(atr[i]);
}
}
doconcat(&ntr); /* execute ## operators */
hs = newhideset(trp->tp->hideset, np);
for (tp=ntr.bp; tp<ntr.lp; tp++) { /* distribute hidesets */
if (tp->type==NAME) {
if (tp->hideset==0)
tp->hideset = hs;
else
tp->hideset = unionhideset(tp->hideset, hs);
}
}
ntr.tp = ntr.bp;
insertrow(trp, ntokc, &ntr);
trp->tp -= rowlen(&ntr);
dofree(ntr.bp);
}
/*
* Gather an arglist, starting in trp with tp pointing at the macro name.
* Return total number of tokens passed, stash number of args found.
* trp->tp is not changed relative to the tokenrow.
*/
int
gatherargs(Tokenrow *trp, Tokenrow **atr, int *narg)
{
int parens = 1;
int ntok = 0;
Token *bp, *lp;
Tokenrow ttr;
int ntokp;
int needspace;
*narg = -1; /* means that there is no macro call */
/* look for the ( */
for (;;) {
trp->tp++;
ntok++;
if (trp->tp >= trp->lp) {
gettokens(trp, 0);
if ((trp->lp-1)->type==END) {
trp->lp -= 1;
trp->tp -= ntok;
return ntok;
}
}
if (trp->tp->type==LP)
break;
if (trp->tp->type!=NL)
return ntok;
}
*narg = 0;
ntok++;
ntokp = ntok;
trp->tp++;
/* search for the terminating ), possibly extending the row */
needspace = 0;
while (parens>0) {
if (trp->tp >= trp->lp)
gettokens(trp, 0);
if (needspace) {
needspace = 0;
makespace(trp);
}
if (trp->tp->type==END) {
trp->lp -= 1;
trp->tp -= ntok;
error(ERROR, "EOF in macro arglist");
return ntok;
}
if (trp->tp->type==NL) {
trp->tp += 1;
adjustrow(trp, -1);
trp->tp -= 1;
makespace(trp);
needspace = 1;
continue;
}
if (trp->tp->type==LP)
parens++;
else if (trp->tp->type==RP)
parens--;
trp->tp++;
ntok++;
}
trp->tp -= ntok;
/* Now trp->tp won't move underneath us */
lp = bp = trp->tp+ntokp;
for (; parens>=0; lp++) {
if (lp->type == LP) {
parens++;
continue;
}
if (lp->type==RP)
parens--;
if (lp->type==DSHARP)
lp->type = DSHARP1; /* ## not special in arg */
if ((lp->type==COMMA && parens==0) || (parens<0 && (lp-1)->type!=LP)) {
if (*narg>=NARG-1)
error(FATAL, "Sorry, too many macro arguments");
ttr.bp = ttr.tp = bp;
ttr.lp = lp;
atr[(*narg)++] = normtokenrow(&ttr);
bp = lp+1;
}
}
return ntok;
}
/*
* substitute the argument list into the replacement string
* This would be simple except for ## and #
*/
void
substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr)
{
Tokenrow tatr;
Token *tp;
int ntok, argno;
for (rtr->tp=rtr->bp; rtr->tp<rtr->lp; ) {
if (rtr->tp->type==SHARP) { /* string operator */
tp = rtr->tp;
rtr->tp += 1;
if ((argno = lookuparg(np, rtr->tp))<0) {
error(ERROR, "# not followed by macro parameter");
continue;
}
ntok = 1 + (rtr->tp - tp);
rtr->tp = tp;
insertrow(rtr, ntok, stringify(atr[argno]));
continue;
}
if (rtr->tp->type==NAME
&& (argno = lookuparg(np, rtr->tp)) >= 0) {
if ((rtr->tp+1)->type==DSHARP
|| (rtr->tp!=rtr->bp && (rtr->tp-1)->type==DSHARP))
insertrow(rtr, 1, atr[argno]);
else {
copytokenrow(&tatr, atr[argno]);
expandrow(&tatr, "<macro>");
insertrow(rtr, 1, &tatr);
dofree(tatr.bp);
}
continue;
}
rtr->tp++;
}
}
/*
* Evaluate the ## operators in a tokenrow
*/
void
doconcat(Tokenrow *trp)
{
Token *ltp, *ntp;
Tokenrow ntr;
int len;
for (trp->tp=trp->bp; trp->tp<trp->lp; trp->tp++) {
if (trp->tp->type==DSHARP1)
trp->tp->type = DSHARP;
else if (trp->tp->type==DSHARP) {
char tt[128];
ltp = trp->tp-1;
ntp = trp->tp+1;
if (ltp<trp->bp || ntp>=trp->lp) {
error(ERROR, "## occurs at border of replacement");
continue;
}
len = ltp->len + ntp->len;
strncpy((char*)tt, (char*)ltp->t, ltp->len);
strncpy((char*)tt+ltp->len, (char*)ntp->t, ntp->len);
tt[len] = '\0';
setsource("<##>", -1, tt);
maketokenrow(3, &ntr);
gettokens(&ntr, 1);
unsetsource();
if (ntr.lp-ntr.bp!=2 || ntr.bp->type==UNCLASS)
error(WARNING, "Bad token %r produced by ##", &ntr);
ntr.lp = ntr.bp+1;
trp->tp = ltp;
makespace(&ntr);
insertrow(trp, (ntp-ltp)+1, &ntr);
dofree(ntr.bp);
trp->tp--;
}
}
}
/*
* tp is a potential parameter name of macro mac;
* look it up in mac's arglist, and if found, return the
* corresponding index in the argname array. Return -1 if not found.
*/
int
lookuparg(Nlist *mac, Token *tp)
{
Token *ap;
if (tp->type!=NAME || mac->ap==NULL)
return -1;
for (ap=mac->ap->bp; ap<mac->ap->lp; ap++) {
if (ap->len==tp->len && strncmp((char*)ap->t,(char*)tp->t,ap->len)==0)
return ap - mac->ap->bp;
}
return -1;
}
/*
* Return a quoted version of the tokenrow (from # arg)
*/
#define STRLEN 512
Tokenrow *
stringify(Tokenrow *vp)
{
static Token t = { STRING };
static Tokenrow tr = { &t, &t, &t+1, 1 };
Token *tp;
uchar s[STRLEN];
uchar *sp = s, *cp;
int i, instring;
*sp++ = '"';
for (tp = vp->bp; tp < vp->lp; tp++) {
instring = tp->type==STRING || tp->type==CCON;
if (sp+2*tp->len >= &s[STRLEN-10]) {
error(ERROR, "Stringified macro arg is too long");
break;
}
if (tp->wslen && (tp->flag&XPWS)==0)
*sp++ = ' ';
for (i=0, cp=tp->t; i<tp->len; i++) {
if (instring && (*cp=='"' || *cp=='\\'))
*sp++ = '\\';
*sp++ = *cp++;
}
}
*sp++ = '"';
*sp = '\0';
sp = s;
t.len = strlen((char*)sp);
t.t = newstring(sp, t.len, 0);
return &tr;
}
/*
* expand a builtin name
*/
void
builtin(Tokenrow *trp, int biname)
{
char *op;
Token *tp;
Source *s;
tp = trp->tp;
trp->tp++;
/* need to find the real source */
s = cursource;
while (s && s->fd==-1)
s = s->next;
if (s==NULL)
s = cursource;
/* most are strings */
tp->type = STRING;
if (tp->wslen) {
*outp++ = ' ';
tp->wslen = 1;
}
op = outp;
*op++ = '"';
switch (biname) {
case KLINENO:
tp->type = NUMBER;
op = outnum(op-1, s->line);
break;
case KFILE: {
char *src = s->filename;
while ((*op++ = *src++) != 0)
if (src[-1] == '\\')
*op++ = '\\';
op--;
break;
}
case KDATE:
strncpy(op, curtime+4, 7);
strncpy(op+7, curtime+20, 4);
op += 11;
break;
case KTIME:
strncpy(op, curtime+11, 8);
op += 8;
break;
default:
error(ERROR, "cpp botch: unknown internal macro");
return;
}
if (tp->type==STRING)
*op++ = '"';
tp->t = (uchar*)outp;
tp->len = op - outp;
outp = op;
}

View File

@@ -1,104 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpp.h"
extern char *optarg;
extern int optind;
extern int verbose;
extern int Cplusplus;
Nlist *kwdefined;
char wd[128];
#define NLSIZE 128
static Nlist *nlist[NLSIZE];
struct kwtab {
char *kw;
int val;
int flag;
} kwtab[] = {
{"if", KIF, ISKW},
{"ifdef", KIFDEF, ISKW},
{"ifndef", KIFNDEF, ISKW},
{"elif", KELIF, ISKW},
{"else", KELSE, ISKW},
{"endif", KENDIF, ISKW},
{"include", KINCLUDE, ISKW},
{"define", KDEFINE, ISKW},
{"undef", KUNDEF, ISKW},
{"line", KLINE, ISKW},
{"warning", KWARNING, ISKW},
{"error", KERROR, ISKW},
{"pragma", KPRAGMA, ISKW},
{"eval", KEVAL, ISKW},
{"defined", KDEFINED, ISDEFINED+ISUNCHANGE},
{"__LINE__", KLINENO, ISMAC+ISUNCHANGE},
{"__FILE__", KFILE, ISMAC+ISUNCHANGE},
{"__DATE__", KDATE, ISMAC+ISUNCHANGE},
{"__TIME__", KTIME, ISMAC+ISUNCHANGE},
{"__STDC__", KSTDC, ISUNCHANGE},
{NULL}
};
unsigned long namebit[077+1];
Nlist *np;
void
setup_kwtab(void)
{
struct kwtab *kp;
Nlist *np;
Token t;
static Token deftoken[1] = {{ NAME, 0, 0, 0, 7, (uchar*)"defined" }};
static Tokenrow deftr = { deftoken, deftoken, deftoken+1, 1 };
for (kp=kwtab; kp->kw; kp++) {
t.t = (uchar*)kp->kw;
t.len = strlen(kp->kw);
np = lookup(&t, 1);
np->flag = kp->flag;
np->val = kp->val;
if (np->val == KDEFINED) {
kwdefined = np;
np->val = NAME;
np->vp = &deftr;
np->ap = 0;
}
}
}
Nlist *
lookup(Token *tp, int install)
{
unsigned int h;
Nlist *np;
uchar *cp, *cpe;
h = 0;
for (cp=tp->t, cpe=cp+tp->len; cp<cpe; )
h += *cp++;
h %= NLSIZE;
np = nlist[h];
while (np) {
if (*tp->t==*np->name && tp->len==np->len
&& strncmp((char*)tp->t, (char*)np->name, tp->len)==0)
return np;
np = np->next;
}
if (install) {
np = new(Nlist);
np->vp = NULL;
np->ap = NULL;
np->flag = 0;
np->val = 0;
np->len = tp->len;
np->name = newstring(tp->t, tp->len, 0);
np->next = nlist[h];
nlist[h] = np;
quickset(tp->t[0], tp->len>1? tp->t[1]:0);
return np;
}
return NULL;
}

View File

@@ -1,370 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpp.h"
static char wbuf[2*OBS];
static char *wbp = wbuf;
/*
* 1 for tokens that don't need whitespace when they get inserted
* by macro expansion
*/
static const char wstab[] = {
0, /* END */
0, /* UNCLASS */
0, /* NAME */
0, /* NUMBER */
0, /* STRING */
0, /* CCON */
1, /* NL */
0, /* WS */
0, /* DSHARP */
0, /* EQ */
0, /* NEQ */
0, /* LEQ */
0, /* GEQ */
0, /* LSH */
0, /* RSH */
0, /* LAND */
0, /* LOR */
0, /* PPLUS */
0, /* MMINUS */
0, /* ARROW */
1, /* SBRA */
1, /* SKET */
1, /* LP */
1, /* RP */
0, /* DOT */
0, /* AND */
0, /* STAR */
0, /* PLUS */
0, /* MINUS */
0, /* TILDE */
0, /* NOT */
0, /* SLASH */
0, /* PCT */
0, /* LT */
0, /* GT */
0, /* CIRC */
0, /* OR */
0, /* QUEST */
0, /* COLON */
0, /* ASGN */
1, /* COMMA */
0, /* SHARP */
1, /* SEMIC */
1, /* CBRA */
1, /* CKET */
0, /* ASPLUS */
0, /* ASMINUS */
0, /* ASSTAR */
0, /* ASSLASH */
0, /* ASPCT */
0, /* ASCIRC */
0, /* ASLSH */
0, /* ASRSH */
0, /* ASOR */
0, /* ASAND */
0, /* ELLIPS */
0, /* DSHARP1 */
0, /* NAME1 */
0, /* DEFINED */
0, /* UMINUS */
};
void
maketokenrow(int size, Tokenrow *trp)
{
trp->max = size;
if (size>0)
trp->bp = (Token *)domalloc(size*sizeof(Token));
else
trp->bp = NULL;
trp->tp = trp->bp;
trp->lp = trp->bp;
}
Token *
growtokenrow(Tokenrow *trp)
{
int ncur = trp->tp - trp->bp;
int nlast = trp->lp - trp->bp;
trp->max = 3*trp->max/2 + 1;
trp->bp = (Token *)realloc(trp->bp, trp->max*sizeof(Token));
if (trp->bp == NULL)
error(FATAL, "Out of memory from realloc");
trp->lp = &trp->bp[nlast];
trp->tp = &trp->bp[ncur];
return trp->lp;
}
/*
* Compare a row of tokens, ignoring the content of WS; return !=0 if different
*/
int
comparetokens(Tokenrow *tr1, Tokenrow *tr2)
{
Token *tp1, *tp2;
tp1 = tr1->tp;
tp2 = tr2->tp;
if (tr1->lp-tp1 != tr2->lp-tp2)
return 1;
for (; tp1<tr1->lp ; tp1++, tp2++) {
if (tp1->type != tp2->type
|| (tp1->wslen==0) != (tp2->wslen==0)
|| tp1->len != tp2->len
|| strncmp((char*)tp1->t, (char*)tp2->t, tp1->len)!=0)
return 1;
}
return 0;
}
/*
* replace ntok tokens starting at dtr->tp with the contents of str.
* tp ends up pointing just beyond the replacement.
* Canonical whitespace is assured on each side.
*/
void
insertrow(Tokenrow *dtr, int ntok, Tokenrow *str)
{
int nrtok = rowlen(str);
dtr->tp += ntok;
adjustrow(dtr, nrtok-ntok);
dtr->tp -= ntok;
movetokenrow(dtr, str);
makespace(dtr);
dtr->tp += nrtok;
makespace(dtr);
}
/*
* make sure there is WS before trp->tp, if tokens might merge in the output
*/
void
makespace(Tokenrow *trp)
{
uchar *tt;
Token *tp = trp->tp;
if (tp >= trp->lp)
return;
if (tp->wslen) {
if (tp->flag&XPWS
&& (wstab[tp->type] || (trp->tp>trp->bp && wstab[(tp-1)->type]))) {
tp->wslen = 0;
return;
}
tp->t[-1] = ' ';
return;
}
if (wstab[tp->type] || (trp->tp>trp->bp && wstab[(tp-1)->type]))
return;
tt = newstring(tp->t, tp->len, 1);
*tt++ = ' ';
tp->t = tt;
tp->wslen = 1;
tp->flag |= XPWS;
}
/*
* Copy an entire tokenrow into another, at tp.
* It is assumed that there is enough space.
* Not strictly conforming.
*/
void
movetokenrow(Tokenrow *dtr, Tokenrow *str)
{
int nby;
/* nby = sizeof(Token) * (str->lp - str->bp); */
nby = (char *)str->lp - (char *)str->bp;
memmove(dtr->tp, str->bp, nby);
}
/*
* Move the tokens in a row, starting at tr->tp, rightward by nt tokens;
* nt may be negative (left move).
* The row may need to be grown.
* Non-strictly conforming because of the (char *), but easily fixed
*/
void
adjustrow(Tokenrow *trp, int nt)
{
int nby, size;
if (nt==0)
return;
size = (trp->lp - trp->bp) + nt;
while (size > trp->max)
growtokenrow(trp);
/* nby = sizeof(Token) * (trp->lp - trp->tp); */
nby = (char *)trp->lp - (char *)trp->tp;
if (nby)
memmove(trp->tp+nt, trp->tp, nby);
trp->lp += nt;
}
/*
* Copy a row of tokens into the destination holder, allocating
* the space for the contents. Return the destination.
*/
Tokenrow *
copytokenrow(Tokenrow *dtr, Tokenrow *str)
{
int len = rowlen(str);
maketokenrow(len, dtr);
movetokenrow(dtr, str);
dtr->lp += len;
return dtr;
}
/*
* Produce a copy of a row of tokens. Start at trp->tp.
* The value strings are copied as well. The first token
* has WS available.
*/
Tokenrow *
normtokenrow(Tokenrow *trp)
{
Token *tp;
Tokenrow *ntrp = new(Tokenrow);
int len;
len = trp->lp - trp->tp;
if (len<=0)
len = 1;
maketokenrow(len, ntrp);
for (tp=trp->tp; tp < trp->lp; tp++) {
*ntrp->lp = *tp;
if (tp->len) {
ntrp->lp->t = newstring(tp->t, tp->len, 1);
*ntrp->lp->t++ = ' ';
if (tp->wslen)
ntrp->lp->wslen = 1;
}
ntrp->lp++;
}
if (ntrp->lp > ntrp->bp)
ntrp->bp->wslen = 0;
return ntrp;
}
/*
* Debugging
*/
void
peektokens(Tokenrow *trp, char *str)
{
Token *tp;
tp = trp->tp;
flushout();
if (str)
fprintf(stderr, "%s ", str);
if (tp<trp->bp || tp>trp->lp)
fprintf(stderr, "(tp offset %ld) ", (long int) (tp - trp->bp));
for (tp=trp->bp; tp<trp->lp && tp<trp->bp+32; tp++) {
if (tp->type!=NL) {
int c = tp->t[tp->len];
tp->t[tp->len] = 0;
fprintf(stderr, "%s", tp->t);
tp->t[tp->len] = c;
}
if (tp->type==NAME) {
fprintf(stderr, tp==trp->tp?"{*":"{");
prhideset(tp->hideset);
fprintf(stderr, "} ");
} else
fprintf(stderr, tp==trp->tp?"{%x*} ":"{%x} ", tp->type);
}
fprintf(stderr, "\n");
fflush(stderr);
}
void
puttokens(Tokenrow *trp)
{
Token *tp;
int len;
uchar *p;
if (verbose)
peektokens(trp, "");
tp = trp->bp;
for (; tp<trp->lp; tp++) {
len = tp->len+tp->wslen;
p = tp->t-tp->wslen;
while (tp<trp->lp-1 && p+len == (tp+1)->t - (tp+1)->wslen) {
tp++;
len += tp->wslen+tp->len;
}
if (len>OBS/2) { /* handle giant token */
if (wbp > wbuf)
write(1, wbuf, wbp-wbuf);
write(1, (char *)p, len);
wbp = wbuf;
} else {
memcpy(wbp, p, len);
wbp += len;
}
if (wbp >= &wbuf[OBS]) {
write(1, wbuf, OBS);
if (wbp > &wbuf[OBS])
memcpy(wbuf, wbuf+OBS, wbp - &wbuf[OBS]);
wbp -= OBS;
}
}
trp->tp = tp;
if (cursource->fd==0)
flushout();
}
void
flushout(void)
{
if (wbp>wbuf) {
write(1, wbuf, wbp-wbuf);
wbp = wbuf;
}
}
/*
* turn a row into just a newline
*/
void
setempty(Tokenrow *trp)
{
trp->tp = trp->bp;
trp->lp = trp->bp+1;
*trp->bp = nltoken;
}
/*
* generate a number
*/
char *
outnum(char *p, int n)
{
if (n>=10)
p = outnum(p, n/10);
*p++ = n%10 + '0';
return p;
}
/*
* allocate and initialize a new string from s, of length l, at offset o
* Null terminated.
*/
uchar *
newstring(uchar *s, int l, int o)
{
uchar *ns = (uchar *)domalloc(l+o+1);
ns[l+o] = '\0';
return (uchar*)strncpy((char*)ns+o, (char*)s, l) - o;
}

View File

@@ -1,128 +0,0 @@
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "cpp.h"
extern int lcc_getopt(int, char *const *, const char *);
extern char *optarg, rcsid[];
extern int optind;
int verbose;
int Mflag; /* only print active include files */
char *objname; /* "src.$O: " */
int Cplusplus = 1;
void
setup(int argc, char **argv)
{
int c, fd, i;
char *fp, *dp;
Tokenrow tr;
extern void setup_kwtab(void);
uchar *includeDirs[ NINCLUDE ] = { 0 };
int numIncludeDirs = 0;
setup_kwtab();
while ((c = lcc_getopt(argc, argv, "MNOVv+I:D:U:F:lg")) != -1)
switch (c) {
case 'N':
for (i=0; i<NINCLUDE; i++)
if (includelist[i].always==1)
includelist[i].deleted = 1;
break;
case 'I':
includeDirs[ numIncludeDirs++ ] = newstring( (uchar *)optarg, strlen( optarg ), 0 );
break;
case 'D':
case 'U':
setsource("<cmdarg>", -1, optarg);
maketokenrow(3, &tr);
gettokens(&tr, 1);
doadefine(&tr, c);
unsetsource();
break;
case 'M':
Mflag++;
break;
case 'v':
fprintf(stderr, "%s %s\n", argv[0], rcsid);
break;
case 'V':
verbose++;
break;
case '+':
Cplusplus++;
break;
default:
break;
}
dp = ".";
fp = "<stdin>";
fd = 0;
if (optind<argc) {
dp = basepath( argv[optind] );
fp = (char*)newstring((uchar*)argv[optind], strlen(argv[optind]), 0);
if ((fd = open(fp, 0)) <= 0)
error(FATAL, "Can't open input file %s", fp);
}
if (optind+1<argc) {
int fdo = creat(argv[optind+1], 0666);
if (fdo<0)
error(FATAL, "Can't open output file %s", argv[optind+1]);
dup2(fdo, 1);
}
if(Mflag)
setobjname(fp);
includelist[NINCLUDE-1].always = 0;
includelist[NINCLUDE-1].file = dp;
for( i = 0; i < numIncludeDirs; i++ )
appendDirToIncludeList( (char *)includeDirs[ i ] );
setsource(fp, fd, NULL);
}
char *basepath( char *fname )
{
char *dp = ".";
char *p;
if ((p = strrchr(fname, '/')) != NULL) {
int dlen = p - fname;
dp = (char*)newstring((uchar*)fname, dlen+1, 0);
dp[dlen] = '\0';
}
return dp;
}
/* memmove is defined here because some vendors don't provide it at
all and others do a terrible job (like calling malloc) */
// -- ouch, that hurts -- ln
#ifndef MACOS_X /* always use the system memmove() on Mac OS X. --ryan. */
#ifdef memmove
#undef memmove
#endif
void *
memmove(void *dp, const void *sp, size_t n)
{
unsigned char *cdp, *csp;
if (n<=0)
return dp;
cdp = dp;
csp = (unsigned char *)sp;
if (cdp < csp) {
do {
*cdp++ = *csp++;
} while (--n);
} else {
cdp += n;
csp += n;
do {
*--cdp = *--csp;
} while (--n);
}
return dp;
}
#endif

View File

@@ -1,754 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<link HREF="mailto:drh@microsoft.com" REV="made" TITLE="David R. Hanson">
<title>The lcc 4.1 Code-Generation Interface</title>
</head>
<body>
<h1>The lcc 4.1 Code-Generation Interface</h1>
<p ALIGN="LEFT"><strong><a HREF="http://www.research.microsoft.com/~cwfraser/">Christopher
W. Fraser</a> and <a HREF="http://www.research.microsoft.com/~drh/">David R. Hanson</a>, <a
HREF="http://www.research.microsoft.com/">Microsoft Research</a></strong></p>
<h2>Contents</h2>
<dir>
<li><a HREF="#intro">Introduction</a> </li>
<li><a HREF="#metrics">5.1 Type Metrics</a></li>
<li><a HREF="#symbols">5.3 Symbols</a> </li>
<li><a HREF="#operators">5.5 Dag Operators</a></li>
<li><a HREF="#flags">5.6 Interface Flags</a></li>
<li><a HREF="#definitions">5.8 Definitions</a></li>
<li><a HREF="#constants">5.9 Constants</a></li>
<li><a HREF="#upcalls">5.12 Upcalls</a></li>
</dir>
<h2><a NAME="intro">Introduction</a></h2>
<p>Version 4.1 is the latest release of <a
HREF="http://www.cs.princeton.edu/software/lcc/">lcc</a>, the ANSI C compiler described in
our book <cite>A Retargetable C Compiler: Design and Implementation</cite>
(Addison-Wesley, 1995, ISBN 0-8053-1670-1). This document summarizes the differences
between the 4.1 code-generation interface and the 3.x interface described in Chap. 5 of <cite>A
Retargetable C Compiler</cite>.</p>
<p>Previous versions of lcc supported only three sizes of integers, two sizes of floats,
and insisted that pointers fit in unsigned integers (see Sec. 5.1 of <cite>A Retargetable
C Compiler</cite>). These assumptions simplified the compiler, and were suitable for
32-bit architectures. But on 64-bit architectures, such as the DEC ALPHA, it's natural to
have four sizes of integers and perhaps three sizes of floats, and on 16-bit
architectures, 32-bit pointers don't fit in unsigned integers. Also, the 3.x constaints
limited the use of lcc's back ends for other languages, such as Java.</p>
<p>Version 4.x removes all of these restrictions: It supports any number of sizes for
integers and floats, and the size of pointers need not be related to the size of any of
the integer types. The major changes in the code-generation interface are:
<ul>
<li>The number of type suffixes has been reduced to 6.</li>
<li>Dag operators are composed of a generic operator, a type suffix, and a size.</li>
<li>Unsigned variants of several operators have been added.</li>
<li>Several interface functions have new signatures.</li>
</ul>
<p>In addition, version 4.x is written in ANSI C and uses the standard I/O library and
other standard C functions.</p>
<p>The sections below parallel the subsections of Chap. 5 of <cite>A Retargetable C
Compiler</cite> and summarize the differences between the 3.x and 4.x code-generation
interface. Unaffected subsections are omitted. Page citations refer to pages in <cite>A
Retargetable C Compiler</cite>.</p>
<h2><a NAME="metrics">5.1 Type Metrics</a></h2>
<p>There are now 10 metrics in an interface record:</p>
<pre>Metrics charmetric;
Metrics shortmetric;
Metrics intmetric;
Metrics longmetric;
Metrics longlongmetric;
Metrics floatmetric;
Metrics doublemetric;
Metrics longdoublemetric;
Metrics ptrmetric;
Metrics structmetric;</pre>
<p>Each of these specifies the size and alignment of the corresponding type. <code>ptrmetric</code>
describes all pointers.</p>
<h2><a NAME="symbols">5.3 Symbols</a></h2>
<p>The actual value of a constant is stored in the <code>u.c.v</code> field of a symbol,
which holds a <code>Value</code>:</p>
<pre>typedef union value {
long i;
unsigned long u;
long double d;
void *p;
void (*g)(void);
} Value;</pre>
<p>The value is stored in the appropriate field according to its type, which is given by
the symbol's <code>type</code> field.</p>
<h2><a NAME="operators">5.5 Dag Operators</a></h2>
<p>The <code>op</code> field of a <code>node</code> structure holds a dag operator, which
consists of a generic operator, a type suffix, and a size indicator. The type suffixes
are:</p>
<pre>enum {
F=FLOAT,
I=INT,
U=UNSIGNED,
P=POINTER,
V=VOID,
B=STRUCT
};
#define sizeop(n) ((n)&lt;&lt;10)</pre>
<p>Given a generic operator <code>o</code>, a type suffix <code>t</code>, and a size <code>s</code>,
a type- and size-specific operator is formed by <code>o+t+sizeop(s)</code>. For example, <code>ADD+F+sizeop(4)</code>
forms the operator <code>ADDF4</code>, which denotes the sum of two 4-byte floats.
Similarly, <code>ADD+F+sizeop(8)</code> forms <code>ADDF8</code>, which denotes 8-byte
floating addition. In the 3.x code-generation interface, <code>ADDF</code> and <code>ADDD</code>
denoted these operations. There was no size indicator in the 3.x operators because the
type suffix supplied both a type and a size.</p>
<p>Table 5.1 lists each generic operator, its valid type suffixes, and the number of <code>kids</code>
and <code>syms</code> that it uses; multiple values for <code>kids</code> indicate
type-specific variants. The notations in the <strong>syms</strong> column give the number
of <code>syms</code> values and a one-letter code that suggests their uses: 1V indicates
that <code>syms[0]</code> points to a symbol for a variable, 1C indicates that <code>syms[0]</code>
is a constant, and 1L indicates that <code>syms[0]</code> is a label. For 1S, <code>syms[0]</code>
is a constant whose value is a size in bytes; 2S adds <code>syms[1]</code>, which is a
constant whose value is an alignment. For most operators, the type suffix and size
indicator denote the type and size of operation to perform and the type and size of the
result.</p>
<table WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0">
<tr>
<td COLSPAN="6" ALIGN="CENTER"><strong>Table 5.1<img SRC="/~drh/resources/dot_clear.gif"
ALT="|" WIDTH="18" HEIGHT="1">Node Operators.</strong></td>
</tr>
<tr>
<td><strong>syms</strong></td>
<td><strong>kids</strong></td>
<td><strong>Operator</strong></td>
<td><strong>Type Suffixes</strong></td>
<td><strong>Sizes</strong></td>
<td><strong>Operation</strong></td>
</tr>
<tr>
<td>1V</td>
<td>0</td>
<td><code>ADDRF</code></td>
<td><code>...P..</code></td>
<td>p</td>
<td>address of a parameter</td>
</tr>
<tr>
<td>1V</td>
<td>0</td>
<td><code>ADDRG</code></td>
<td><code>...P..</code></td>
<td>p</td>
<td>address of a global</td>
</tr>
<tr>
<td>1V</td>
<td>0</td>
<td><code>ADDRL</code></td>
<td><code>...P..</code></td>
<td>p</td>
<td>address of a local</td>
</tr>
<tr>
<td>1C</td>
<td>0</td>
<td><code>CNST</code></td>
<td><code>FIUP..</code></td>
<td>fdx csilh p</td>
<td>constant</td>
</tr>
<tr ALIGN="LEFT" VALIGN="TOP">
<td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>1</td>
<td><code>BCOM</code></td>
<td><code>.IU...</code></td>
<td>ilh</td>
<td>bitwise complement</td>
</tr>
<tr>
<td>1S</td>
<td>1</td>
<td><code>CVF</code></td>
<td><code>FI....</code></td>
<td>fdx ilh</td>
<td>convert from float</td>
</tr>
<tr>
<td>1S</td>
<td>1</td>
<td><code>CVI</code></td>
<td><code>FIU...</code></td>
<td>fdx csilh csilhp</td>
<td>convert from signed integer</td>
</tr>
<tr>
<td>1S</td>
<td>1</td>
<td><code>CVP</code></td>
<td><code>..U..</code></td>
<td>p</td>
<td>convert from pointer</td>
</tr>
<tr>
<td>1S</td>
<td>1</td>
<td><code>CVU</code></td>
<td><code>.IUP..</code></td>
<td>csilh p</td>
<td>convert from unsigned integer</td>
</tr>
<tr>
<td></td>
<td>1</td>
<td><code>INDIR</code></td>
<td><code>FIUP.B</code></td>
<td>fdx csilh p</td>
<td>fetch</td>
</tr>
<tr>
<td></td>
<td>1</td>
<td><code>NEG</code></td>
<td><code>FI....</code></td>
<td>fdx ilh</td>
<td>negation</td>
</tr>
<tr>
<td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>2</td>
<td><code>ADD</code></td>
<td><code>FIUP..</code></td>
<td>fdx ilh ilhp p</td>
<td>addition</td>
</tr>
<tr>
<td></td>
<td>2</td>
<td><code>BAND</code></td>
<td><code>.IU...</code></td>
<td>ilh</td>
<td>bitwise AND</td>
</tr>
<tr>
<td></td>
<td>2</td>
<td><code>BOR</code></td>
<td><code>.IU...</code></td>
<td>ilh</td>
<td>bitwise inclusive OR</td>
</tr>
<tr>
<td></td>
<td>2</td>
<td><code>BXOR</code></td>
<td><code>.IU...</code></td>
<td>ilh</td>
<td>bitwise exclusive OR</td>
</tr>
<tr>
<td></td>
<td>2</td>
<td><code>DIV</code></td>
<td><code>FIU...</code></td>
<td>fdx ilh</td>
<td>division</td>
</tr>
<tr>
<td></td>
<td>2</td>
<td><code>LSH</code></td>
<td><code>.IU...</code></td>
<td>ilh</td>
<td>left shift</td>
</tr>
<tr>
<td></td>
<td>2</td>
<td><code>MOD</code></td>
<td><code>.IU...</code></td>
<td>ilh</td>
<td>modulus</td>
</tr>
<tr>
<td></td>
<td>2</td>
<td><code>MUL</code></td>
<td><code>FIU...</code></td>
<td>fdx ilh</td>
<td>multiplication</td>
</tr>
<tr>
<td></td>
<td>2</td>
<td><code>RSH</code></td>
<td><code>.IU...</code></td>
<td>ilh</td>
<td>right shift</td>
</tr>
<tr>
<td></td>
<td>2</td>
<td><code>SUB</code></td>
<td><code>FIUP..</code></td>
<td>fdx ilh ilhp p</td>
<td>subtraction</td>
</tr>
<tr>
<td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>2S</td>
<td>2</td>
<td><code>ASGN</code></td>
<td><code>FIUP.B</code></td>
<td>fdx csilh p</td>
<td>assignment</td>
</tr>
<tr>
<td>1L</td>
<td>2</td>
<td><code>EQ</code></td>
<td><code>FIU...</code></td>
<td>fdx ilh ilhp</td>
<td>jump if equal</td>
</tr>
<tr>
<td>1L</td>
<td>2</td>
<td><code>GE</code></td>
<td><code>FIU...</code></td>
<td>fdx ilh ilhp</td>
<td>jump if greater than or equal</td>
</tr>
<tr>
<td>1L</td>
<td>2</td>
<td><code>GT</code></td>
<td><code>FIU...</code></td>
<td>fdx ilh ilhp</td>
<td>jump if greater than</td>
</tr>
<tr>
<td>1L</td>
<td>2</td>
<td><code>LE</code></td>
<td><code>FIU...</code></td>
<td>fdx ilh ilhp</td>
<td>jump if less than or equal</td>
</tr>
<tr>
<td>1L</td>
<td>2</td>
<td><code>LT</code></td>
<td><code>FIU...</code></td>
<td>fdx ilh ilhp</td>
<td>jump if less than</td>
</tr>
<tr>
<td>1L</td>
<td>2</td>
<td><code>NE</code></td>
<td><code>FIU...</code></td>
<td>fdx ilh ilhp</td>
<td>jump if not equal</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>2S</td>
<td>1</td>
<td><code>ARG</code></td>
<td><code>FIUP.B</code></td>
<td>fdx ilh p</td>
<td>argument</td>
</tr>
<tr>
<td>1</td>
<td>1 or 2</td>
<td><code>CALL</code></td>
<td><code>FIUPVB</code></td>
<td>fdx ilh p</td>
<td>function call</td>
</tr>
<tr>
<td></td>
<td>1</td>
<td><code>RET</code></td>
<td><code>FIUPV.</code></td>
<td>fdx ilh p</td>
<td>return from function</td>
</tr>
<tr>
<td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>1</td>
<td><code>JUMP</code></td>
<td><code>....V.</code></td>
<td></td>
<td>unconditional jump</td>
</tr>
<tr>
<td>1L</td>
<td>0</td>
<td><code>LABEL</code></td>
<td><code>....V.</code></td>
<td></td>
<td>label definition</td>
</tr>
</table>
<p>The entries in the <strong>Sizes</strong> column indicate sizes of the operators that
back ends must implement. Letters denote the size of float (f), double (d), long double
(x), character (c), short integer (s), integer (i), long integer (l), &quot;long
long&quot; integer (h) , and pointer (p). These sizes are separated into sets for each
type suffix, except that a single set is used for both I and U when the set for I is
identical to the set for U.</p>
<p>The actual values for the size indicators, fdxcsilhp, depend on the target. A
specification like <code>ADDF</code>f denotes the operator <code>ADD+F+sizeop(</code>f<code>)</code>,
where &quot;f&quot; is replaced by a target-dependent value, e.g., <code>ADDF4</code> and <code>ADDF8</code>.
For example, back ends must implement the following <code>CVI</code> and <code>MUL</code>
operators.</p>
<blockquote>
<p><code>CVIF</code>f <code>CVIF</code>d <code>CVIF</code>x<br>
<code>CVII</code>c <code>CVII</code>s <code>CVII</code>i <code>CVII</code>l <code>CVII</code>h<br>
<code>CVIU</code>c <code>CVIU</code>s <code>CVIU</code>i <code>CVIU</code>l <code>CVIU</code>h
<code>CVIU</code>p<br>
<br>
<code>MULF</code>f <code>MULF</code>d <code>MULF</code>x<br>
<code>MULI</code>i <code>MULI</code>l <code>MULI</code>h<br>
<code>MULU</code>i <code>MULU</code>l <code>MULU</code>h</p>
</blockquote>
<p>On most platforms, there are fewer than three sizes of floats and six sizes of
integers, and pointers are usually the same size as one of the integers. And lcc doesn't
support the &quot;long long&quot; type, so h is not currently used. So the set of
platform-specific operators is usually smaller than the list above suggests. For example,
the X86, SPARC, and MIPS back ends implement the following <code>CVI</code> and <code>MUL</code>
operators.</p>
<blockquote>
<p><code>CVIF</code>4 <code>CVIF</code>8<br>
<code>CVII</code>1 <code>CVII</code>2 <code>CVII</code>4<br>
<code>CVIU</code>1 <code>CVIU</code>2 <code>CVIU</code>4 <br>
<br>
<code>MULF</code>4 <code>MULF</code>8<br>
<code>MULI</code>4<br>
<code>MULU</code>4</p>
</blockquote>
<p>The set of operators is thus target-dependent; for example, <code>ADDI8</code> appears
only if the target supports an 8-byte integer type. <a
HREF="ftp://ftp.cs.princeton.edu/pub/packages/lcc/contrib/ops.c"><code>ops.c</code></a> is
a program that, given a set of sizes, prints the required operators and their values,
e.g.,</p>
<blockquote>
<pre>% <em>ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4</em>
...
CVIF4=4225 CVIF8=8321
CVII1=1157 CVII2=2181 CVII4=4229
CVIU1=1158 CVIU2=2182 CVIU4=4230
...
MULF4=4561 MULF8=8657
MULI4=4565
MULU4=4566
...
131 operators</pre>
</blockquote>
<p>The type suffix for a conversion operator denotes the type of the result and the size
indicator gives the size of the result. For example, <code>CVUI4</code> converts an
unsigned (<code>U</code>) to a 4-byte signed integer (<code>I4</code>). The <code>syms[0]</code>
field points to a symbol-table entry for an integer constant that gives the size of the
source operand. For example, if <code>syms[0]</code> in a <code>CVUI4</code> points to a
symbol-table entry for 2, the conversion widens a 2-byte unsigned integer to a 4-byte
signed integer. Conversions that widen unsigned integers zero-extend; those that widen
signed integers sign-extend.</p>
<p>The front end composes conversions between types <em>T</em><sub>1</sub> and <em>T</em><sub>2</sub>
by widening <em>T</em><sub>1</sub> to its &quot;supertype&quot;, if necessary, converting
that result to <em>T</em><sub>2</sub>'s supertype, then narrowing the result to <em>T</em><sub>2</sub>,
if necessary. The following table lists the supertypes; omitted entries are their own
supertypes.</p>
<blockquote>
<table BORDER="0" CELLPADDING="0" CELLSPACING="0">
<tr>
<td><strong>Type</strong></td>
<td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td>
<td><strong>Supertype</strong></td>
</tr>
<tr>
<td>signed char</td>
<td></td>
<td>int</td>
</tr>
<tr>
<td>signed short</td>
<td></td>
<td>int</td>
</tr>
<tr ALIGN="LEFT" VALIGN="TOP">
<td>unsigned char</td>
<td></td>
<td>int, if sizeof (char) &lt; sizeof (int)<br>
unsigned, otherwise</td>
</tr>
<tr ALIGN="LEFT" VALIGN="TOP">
<td>unsigned short</td>
<td></td>
<td>int, if sizeof (short) &lt; sizeof (int)<br>
unsigned, otherwise</td>
</tr>
<tr ALIGN="LEFT" VALIGN="TOP">
<td>void *</td>
<td></td>
<td>an unsigned type as large as a pointer</td>
</tr>
</table>
</blockquote>
<p>Pointers are converted to an unsigned type of the same size, even when that type is not
one of the integer types.</p>
<p>For example, the front end converts a signed short to a float by first converting it to
an int and then to a float. It converts an unsigned short to an int with a single <code>CVUI</code>i
conversion, when shorts are smaller than ints.</p>
<p>There are now signed and unsigned variants of <code>ASGN</code>, <code>INDIR</code>, <code>BCOM</code>,
<code>BOR</code>, <code>BXOR</code>, <code>BAND</code>, <code>ARG</code>, <code>CALL</code>,
and <code>RET</code> to simplify code generation on platforms that use different
instructions or register set for signed and unsigned operations. Likewise there are now
pointer variants of <code>ASGN</code>, <code>INDIR</code>, <code>ARG</code>, <code>CALL</code>,
and <code>RET</code>.</p>
<h2><a NAME="flags">5.6 Interface Flags</a></h2>
<pre>unsigned unsigned_char:1;</pre>
<p>tells the front end whether plain characters are signed or unsigned. If it's zero, char
is a signed type; otherwise, char is an unsigned type.</p>
<p>All the interface flags can be set by command-line options, e.g., <code>-Wf-unsigned_char=1</code>
causes plain characters to be unsigned.</p>
<h2><a NAME="definitions">5.8 Definitions</a></h2>
<p>The front end announces local variables by calling</p>
<pre>void (*local)(Symbol);</pre>
<p>It announces temporaries likewise; these have the symbol's <code>temporary</code> flag
set, which indicates that the symbol will be used only in the next call to <code>gen</code>.
If a temporary's <code>u.t.cse</code> field is nonnull, it points to the node that
computes the value assigned to the temporary; see page 346.</p>
<p>The front end calls</p>
<pre>void (*address)(Symbol p, Symbol q, long n);</pre>
<p>to initialize <code>q</code> to a symbol that represents an address of the form <em>x</em>+<code>n</code>,
where <em>x</em> is the address represented by <code>p</code> and the long integer <code>n</code>
is positive or negative.</p>
<h2><a NAME="constants">5.9 Constants</a></h2>
<p>The interface function</p>
<pre>void (*defconst)(int suffix, int size, Value v);</pre>
<p>initializes constants. defconst emits directives to define a cell and initialize it to
a constant value. v is the constant value, suffix identifies the type of the value, and
size is the size of the value in bytes. The value of suffix indicates which field of v
holds the value, as shown in the following table.</p>
<blockquote>
<table BORDER="0" CELLPADDING="1" CELLSPACING="1">
<tr>
<td><strong>suffix</strong></td>
<td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td>
<td><strong>v Field</strong></td>
<td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td>
<td><strong>size</strong></td>
</tr>
<tr>
<td><code>F</code></td>
<td></td>
<td><code>v.d</code></td>
<td></td>
<td>float, double, long double</td>
</tr>
<tr>
<td><code>I</code></td>
<td></td>
<td><code>v.i</code></td>
<td></td>
<td>signed char, signed short, signed int, signed long</td>
</tr>
<tr>
<td><code>U</code></td>
<td></td>
<td><code>v.u</code></td>
<td></td>
<td>unsigned char, unsigned short, unsigned int, unsigned long</td>
</tr>
<tr>
<td><code>P</code></td>
<td></td>
<td><code>v.p</code></td>
<td></td>
<td>void *</td>
</tr>
</table>
</blockquote>
<p><code>defconst</code> must narrow <code>v.</code>x when <code>size</code> is less than <code>sizeof</code>
<code>v.</code>x; e.g., to emit an unsigned char, <code>defconst</code> should emit <code>(unsigned
char)v.i</code>.</p>
<h2><a NAME="upcalls">5.12 Upcalls</a></h2>
<p>lcc 4.x uses standard I/O and its I/O functions have been changed accordingly. lcc
reads input from the standard input, emits code to the standard output, and writes
diagnostics to the standard error output. It uses <code>freopen</code> to redirect these
streams to explicit files, when necessary.</p>
<p><code>bp</code>, <code>outflush</code>, and <code>outs</code> have been eliminated.</p>
<pre>extern void fprint(FILE *f, const char *fmt, ...);
extern void print(const char *fmt, ...);</pre>
<p>print formatted data to file <code>f</code> (<code>fprint</code>) or the standard
output (<code>print</code>). These functions are like standard C's <code>printf</code> and
<code>fprintf</code>, but support only some of the standard conversion specifiers and do
not support flags, precision, and field-width specifications. They support the following
new conversion specifiers in addition to those described on page 99.</p>
<blockquote>
<table BORDER="0" CELLPADDING="0" CELLSPACING="0">
<tr>
<td><strong>Specifiers</strong></td>
<td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td>
<td><strong>Corresponding printf Specifiers</strong></td>
</tr>
<tr>
<td><code>%c</code></td>
<td></td>
<td><code>%c</code></td>
</tr>
<tr>
<td><code>%d %D</code></td>
<td></td>
<td><code>%d %ld</code></td>
</tr>
<tr>
<td><code>%u %U</code></td>
<td></td>
<td><code>%u %lu</code></td>
</tr>
<tr>
<td><code>%x %X</code></td>
<td></td>
<td><code>%x %lx</code></td>
</tr>
<tr>
<td><code>%f %e %g</code></td>
<td></td>
<td><code>%e %f %g</code></td>
</tr>
<tr ALIGN="LEFT" VALIGN="TOP">
<td><code>%p</code></td>
<td></td>
<td>Converts the corresponding void * argument to unsigned long and prints it with the <code>printf</code>
<code>%#x</code> specifier or just <code>%x</code> when the argument is null.</td>
</tr>
<tr ALIGN="LEFT" VALIGN="TOP">
<td><code>%I</code></td>
<td></td>
<td>Prints the number of spaces given by the corresponding argument.</td>
</tr>
</table>
</blockquote>
<pre>#define generic(op) ((op)&amp;0x3F0)
#define specific(op) ((op)&amp;0x3FF)</pre>
<p><code>generic(op)</code> returns the generic variant of <code>op</code>; that is,
without its type suffix and size indicator. <code>specific(op)</code> returns the
type-specific variant of <code>op</code>; that is, without its size indicator.</p>
<p><code>newconst</code> has been replaced by</p>
<pre>extern Symbol intconst(int n);</pre>
<p>which installs the integer constant <code>n</code> in the symbol table, if necessary,
and returns a pointer to the symbol-table entry.</p>
<hr>
<address>
<a HREF="http://www.research.microsoft.com/~cwfraser/">Chris Fraser</a> / <a
HREF="mailto:cwfraser@microsoft.com">cwfraser@microsoft.com</a><br>
<a HREF="http://www.research.microsoft.com/~drh/">David Hanson</a> / <a
HREF="mailto:drh@microsoft.com">drh@microsoft.com</a><br>
$Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $
</address>
</body>
</html>

View File

@@ -1,83 +0,0 @@
.\" $Id: bprint.1 145 2001-10-17 21:53:10Z timo $
.TH BPRINT 1 "local \- $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $"
.SH NAME
bprint \- expression profiler
.SH SYNOPSIS
.B bprint
[
.I option ...
]
[
.I file ...
]
.SH DESCRIPTION
.I bprint
produces on the standard output a listing of the programs compiled by
.I lcc
with the
.B \-b
option.
Executing an
.B a.out
so compiled appends profiling data to
.BR prof.out .
The first token of each expression in the listing is preceded
by the number of times it was executed
enclosed in angle brackets as determined from the data in
.BR prof.out .
.I bprint
interprets the following options.
.TP
.B \-c
Compress the
.B prof.out
file, which otherwise grows with every execution of
.BR a.out .
.TP
.B \-b
Print an annotated listing as described above.
.TP
.B \-n
Include line numbers in the listing.
.TP
.B \-f
Print only the number of invocations of each function.
A second
.B \-f
summarizes call sites instead of callers.
.TP
.BI \-I \*Sdir
specifies additional directories in which to seek
files given in
.B prof.out
that do not begin with `/'.
.PP
If any file names are given, only the requested data for those files are printed
in the order presented.
If no options are given,
.B \-b
is assumed.
.SH FILES
.PP
.ta \w'$LCCDIR/liblcc.{a,lib}XX'u
.nf
prof.out profiling data
$LCCDIR/liblcc.{a,lib} \fIlcc\fP-specific library
.SH "SEE ALSO"
.IR lcc (1),
.IR prof (1)
.SH BUGS
Macros and comments can confuse
.I bprint
because it uses post-expansion source coordinates
to annotate pre-expansion source files.
If
.I bprint
sees that it's about to print a statement count
.I inside
a number or identifier, it moves the count to just
.I before
the token.
.PP
Can't cope with an ill-formed
.BR prof.out .

Binary file not shown.

View File

@@ -1,796 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<link HREF="mailto:drh@cs.princeton.edu" REV="made" TITLE="David R. Hanson">
<title>Installing lcc</title>
</head>
<body>
<h1>Installing lcc</h1>
<p ALIGN="LEFT"><strong><a HREF="http://www.research.microsoft.com/~cwfraser/">Christopher
W. Fraser</a> and <a HREF="http://www.research.microsoft.com/~drh/">David R. Hanson</a>, <a
HREF="http://www.research.microsoft.com/">Microsoft Research</a></strong></p>
<h2>Contents</h2>
<dir>
<li><a HREF="#intro">Introduction</a></li>
<li><a HREF="#unix">Installation on UNIX</a></li>
<li><a HREF="#driver">Building the Driver</a></li>
<li><a HREF="#rcc">Building the Compiler and Accessories</a></li>
<li><a HREF="#win32">Installation on Windows NT 4.0 and Windows 95/98</a></li>
<li><a HREF="#bugs">Reporting Bugs</a></li>
<li><a HREF="#mailinglist">Keeping in Touch</a></li>
</dir>
<h2><a NAME="intro">Introduction</a></h2>
<p><a HREF="http://www.cs.princeton.edu/software/lcc/">lcc</a> is the ANSI C compiler
described in our book <cite>A Retargetable C Compiler: Design and Implementation</cite>
(Addison-Wesley, 1995, ISBN 0-8053-1670-1).</p>
<p>If you're installing lcc on a UNIX system, read the remainder of this section and
continue with the next section. If you're installing lcc on a Windows NT 4.0 or Windows
95/98 system, and you intend only to <u>use</u> lcc, you can run the <a
href="ftp://ftp.cs.princeton.edu/pub/packages/lcc/lcc41.exe">InstallShield executable</a>,
which installs the binaries and the documentation. If you want to <u>modify</u> lcc or <u>rebuild</u>
it from the source files, you need the <a
href="ftp://ftp.cs.princeton.edu/packages/lcc/lcc41.zip">complete distribution</a>, and
you should read the rest of the section, the following three sections, and the <a
HREF="#win32">Windows NT/95/98</a> section.</p>
<p>Extract the distribution into its own directory. All non-absolute paths below are
relative to this directory. The distribution holds the following subdirectories.</p>
<blockquote>
<table BORDER="0" CELLPADDING="1" CELLSPACING="1" WIDTH="80%">
<tr>
<td><a HREF="../src"><code>src</code></a></td>
<td></td>
<td>source code</td>
</tr>
<tr>
<td><a HREF="../etc"><code>etc</code></a></td>
<td></td>
<td>driver, accessories</td>
</tr>
<tr>
<td><a HREF="../lib"><code>lib</code></a></td>
<td></td>
<td>runtime library source code</td>
</tr>
<tr>
<td><a HREF="../cpp"><code>cpp</code></a></td>
<td></td>
<td>preprocessor source code</td>
</tr>
<tr>
<td><a HREF="../lburg"><code>lburg</code></a></td>
<td></td>
<td>code-generator generator source code</td>
</tr>
<tr>
<td><a HREF="../doc"><code>doc</code></a></td>
<td></td>
<td>this document, man pages</td>
</tr>
<tr>
<td><code><a HREF="../include">include</a>/*/*</code></td>
<td></td>
<td>include files</td>
</tr>
<tr>
<td><a HREF="../tst"><code>tst</code></a></td>
<td></td>
<td>test suite</td>
</tr>
<tr>
<td><code><a HREF="../alpha">alpha</a>/*/tst</code></td>
<td></td>
<td>ALPHA test outputs</td>
</tr>
<tr>
<td><code><a HREF="../mips">mips</a>/*/tst</code></td>
<td></td>
<td>MIPS test outputs</td>
</tr>
<tr>
<td><code><a HREF="../sparc">sparc</a>/*/tst</code></td>
<td></td>
<td>SPARC test outputs</td>
</tr>
<tr>
<td><code><a HREF="../x86">x86</a>/*/tst</code></td>
<td></td>
<td>X86 test outputs</td>
</tr>
</table>
</blockquote>
<p><code>doc/install.html</code> is the HTML file for this document. <a HREF="4.html"><code>doc/4.html</code></a>
describes the internal differences between lcc 3.x and 4.1.</p>
<p>The installation makefile is designed so that lcc can be installed from a read-only
file system or directory, which is common in networked environments, so the distribution
can be unloaded on a central file server. <strong>You will need an existing ANSI/ISO C
compiler to build and install lcc.</strong></p>
<h2><a NAME="unix">Installation on UNIX</a></h2>
<p>The compilation components (the preprocessor, include files, and compiler proper, etc.)
are installed in a single <em>build directory</em>. On multi-platform systems supported by
a central file server, it's common to store the build directory in a location specific to
the platform and to the version of lcc, and to point a symbolic link to this location. For
example,</p>
<blockquote>
<pre>% ln -s /usr/local/lib/lcc-4.1/sparc-solaris /usr/local/lib/lcc</pre>
</blockquote>
<p>points <code>/usr/local/lib/lcc</code> to a build directory for lcc version 4.1 on the
SPARC under Solaris. Links into <code>/usr/local/lib</code> are created for the programs <code>lcc</code>
and <code>bprint</code>. Thus, a new distribution can be installed by building it in its
own build directory and changing one symbolic link to point to that directory. If these
conventions or their equivalents are followed, the host-specific parts of the driver
program, <code>lcc</code>, can be used unmodified.</p>
<p>Installation on a UNIX system involves the following steps. Below, the build directory
is referred to as <code>BUILDDIR</code>.
<ol>
<li>Create the build directory, using a version- and platform-specific naming convention as
suggested above, and record the name of this directory in the <code>BUILDDIR</code>
environment variable:<blockquote>
<pre>% setenv BUILDDIR /usr/local/lib/lcc-4.1/sparc-solaris
% mkdir -p $BUILDDIR</pre>
</blockquote>
<p>Here and below, commands assume the C shell. Also, you'll need a version of <code>mkdir</code>
that supports the <code>-p</code> option, which creates intermediate directories as
necessary.</p>
</li>
<li>Copy the man pages to the repository for local man pages, e.g.,<blockquote>
<pre>% cp doc/*.1 /usr/local/man/man1</pre>
</blockquote>
<p>Some users copy the man pages to the build directory and create the appropriate
symbolic links, e.g., </p>
<blockquote>
<pre>% cp doc/*.1 $BUILDDIR
% ln -s $BUILDDIR/*.1 /usr/local/man/man1</pre>
</blockquote>
</li>
<li>Platform-specific include files are in directories named <code>include/</code><em>target</em><code>/</code><em>os</em>.
Create the include directory in the build directory, and copy the include hierarchy for
your platform to this directory, e.g.,<blockquote>
<pre>% mkdir $BUILDDIR/include
% cp -p -R include/sparc/solaris/* $BUILDDIR/include</pre>
</blockquote>
<p>Again, some users create a symbolic link to the appropriate directory in the
distribution instead of copying the include files. For example, at Princeton, the
distributions are stored under <code>/proj/pkg/lcc</code>, so the included files are
&quot;installed&quot; by creating one symbolic link: </p>
<blockquote>
<pre>% ln -s /proj/pkg/lcc/4.1/include/sparc/solaris $BUILDDIR/include</pre>
</blockquote>
<p>If you're installing lcc on Linux, you <em>must</em> also plant a symbolic link named <code>gcc</code>
to gcc's library directory, because lcc uses gcc's C preprocessor and most of gcc's header
files:</p>
<blockquote>
<pre>% ln -s /usr/lib/gcc-lib/i486-linux/2.7.2.2 $BUILDDIR/gcc</pre>
</blockquote>
<p>The library directory shown above may be different on your Linux machine; to determine
the correct directory, browse <code>/usr/lib/gcc-lib</code>, or execute</p>
<blockquote>
<pre>% cc -v tst/8q.c</pre>
</blockquote>
<p>and examine the diagnostic output. Make sure that <code>$BUILDDIR/gcc/cpp</code> and <code>$BUILDDIR/gcc/include</code>
point to, respectively, gcc's C preprocessor and header files. On Linux, lcc looks for
include files in <code>$BUILDDIR/include</code>, <code>$BUILDDIR/gcc/include</code>, and <code>/usr/include</code>,
in that order; see <a HREF="#driver"><em>Building the Driver</em></a> and <a
href="../etc/linux.c"><code>etc/linux.c</code></a> for details.</p>
</li>
<li>The <a HREF="../makefile"><code>makefile</code></a> includes the file named by the <code>CUSTOM</code>
macro; the default is <code>custom.mk</code>, and an empty <code>custom.mk</code> is
included in the distribution. If desired, prepare a site-specification customization file
and define <code>CUSTOM</code> to the path of that file when invoking make in steps 5 and
6, e.g.,<blockquote>
<pre>make CUSTOM=/users/drh/solaris.mk</pre>
</blockquote>
<p>You can, for example, use customization files to record site-specific values for macros
instead of using environment variables, and to record targets for the steps in this list.</p>
</li>
<li>Build the host-specific driver, creating a custom host-specific part, if necessary. See <a
HREF="#driver"><em>Building the Driver</em></a>.</li>
<li>Build the preprocessor, compiler proper, library, and other accessories. See <a
HREF="#rcc"><em>Building the Compiler</em></a>.</li>
<li>Plant symbolic links to the build directory and to the installed programs, e.g.,<blockquote>
<pre>% ln -s $BUILDDIR /usr/local/lib/lcc
% ln -s /usr/local/lib/{lcc,bprint} /usr/local/bin</pre>
</blockquote>
<p>Some users copy <code>bprint</code> and <code>lcc</code> into <code>/usr/local/bin</code>
instead of creating symbolic links. The advantange of creating the links for <code>lcc</code>
and <code>bprint</code> as shown is that, once established, they point indirectly to
whatever <code>/usr/local/lib/lcc</code> points to; installing a new version of lcc, say,
4.2, can be done by changing <code>/usr/local/lib/lcc</code> to point to the 4.2 build
directory.</p>
</li>
</ol>
<h2><a NAME="driver">Building the Driver</a></h2>
<p>The preprocessor, compiler, assembler, and loader are invoked by a driver program, <code>lcc</code>,
which is similar to <code>cc</code> on most systems. It's described in the man page <code>doc/lcc.1</code>.
The driver is built by combining the host-independent part, <a href="../etc/lcc.c"><code>etc/lcc.c</code></a>,
with a small host-specific part. Distributed host-specific parts are named <code>etc/</code><em>os</em><code>.c</code>,
where <em>os</em> is the name of the operating system for the host on which <code>lcc</code>
is being installed. If you're following the installations conventions described above, you
can probably use one of the host-specific parts unmodified; otherwise, pick one that is
closely related to your platform, copy it to <em>whatever</em><code>.c</code>, and edit it
as described below. You should not have to edit <code>etc/lcc.c</code>.</p>
<p>We'll use <a HREF="../etc/solaris.c"><code>etc/solaris.c</code></a> as an example in
describing how the host-specific part works. This example illustrates all the important
features. Make sure you have the environment variable <code>BUILDDIR</code> set correctly,
and build the driver with a <code>make</code> command, e.g.,</p>
<blockquote>
<pre>% make HOSTFILE=etc/solaris.c lcc
cc -g -c -DTEMPDIR=\&quot;/tmp\&quot; -o /usr/local/lib/lcc-4.1/sparc-solaris/lcc.o etc/lcc.c
cc -g -c -o /usr/local/lib/lcc-4.1/sparc-solaris/host.o etc/solaris.c
cc -g -o /usr/local/lib/lcc-4.1/sparc-solaris/lcc /usr/local/lib/lcc-4.1/sparc-solaris/lcc.o /usr/local/lib/lcc-4.1/sparc-solaris/host.o</pre>
</blockquote>
<p>The symbolic name <code>HOSTFILE</code> specifies the path to the host-specific part,
either one in the distribution or <em>whatever</em><code>.c</code>. Some versions of make
may require the <code>-e</code> option in order to read the environment.</p>
<p>Here's <code>etc/solaris.c</code>:</p>
<blockquote>
<pre>/* Sparcs running Solaris 2.5.1 at CS Dept., Princeton University */
#include &lt;string.h&gt;
static char rcsid[] = &quot;$ Id: solaris.c,v 1.10 1998/09/14 20:36:33 drh Exp $&quot;;
#ifndef LCCDIR
#define LCCDIR &quot;/usr/local/lib/lcc/&quot;
#endif
#ifndef SUNDIR
#define SUNDIR &quot;/opt/SUNWspro/SC4.2/lib/&quot;
#endif
char *suffixes[] = { &quot;.c&quot;, &quot;.i&quot;, &quot;.s&quot;, &quot;.o&quot;, &quot;.out&quot;, 0 };
char inputs[256] = &quot;&quot;;
char *cpp[] = { LCCDIR &quot;cpp&quot;,
&quot;-D__STDC__=1&quot;, &quot;-Dsparc&quot;, &quot;-D__sparc__&quot;, &quot;-Dsun&quot;, &quot;-D__sun__&quot;, &quot;-Dunix&quot;,
&quot;$1&quot;, &quot;$2&quot;, &quot;$3&quot;, 0 };
char *include[] = { &quot;-I&quot; LCCDIR &quot;include&quot;, &quot;-I/usr/local/include&quot;,
&quot;-I/usr/include&quot;, 0 };
char *com[] = { LCCDIR &quot;rcc&quot;, &quot;-target=sparc/solaris&quot;,
&quot;$1&quot;, &quot;$2&quot;, &quot;$3&quot;, 0 };
char *as[] = { &quot;/usr/ccs/bin/as&quot;, &quot;-Qy&quot;, &quot;-s&quot;, &quot;-o&quot;, &quot;$3&quot;, &quot;$1&quot;, &quot;$2&quot;, 0 };
char *ld[] = { &quot;/usr/ccs/bin/ld&quot;, &quot;-o&quot;, &quot;$3&quot;, &quot;$1&quot;,
SUNDIR &quot;crti.o&quot;, SUNDIR &quot;crt1.o&quot;,
SUNDIR &quot;values-xa.o&quot;, &quot;$2&quot;, &quot;&quot;,
&quot;-Y&quot;, &quot;P,&quot; SUNDIR &quot;:/usr/ccs/lib:/usr/lib&quot;, &quot;-Qy&quot;,
&quot;-L&quot; LCCDIR, &quot;-llcc&quot;, &quot;-lm&quot;, &quot;-lc&quot;, SUNDIR &quot;crtn.o&quot;, 0 };
extern char *concat(char *, char *);
int option(char *arg) {
if (strncmp(arg, &quot;-lccdir=&quot;, 8) == 0) {
cpp[0] = concat(&amp;arg[8], &quot;/cpp&quot;);
include[0] = concat(&quot;-I&quot;, concat(&amp;arg[8], &quot;/include&quot;));
ld[12] = concat(&quot;-L&quot;, &amp;arg[8]);
com[0] = concat(&amp;arg[8], &quot;/rcc&quot;);
} else if (strcmp(arg, &quot;-p&quot;) == 0) {
ld[5] = SUNDIR &quot;mcrt1.o&quot;;
ld[10] = &quot;P,&quot; SUNDIR &quot;libp:/usr/ccs/lib/libp:/usr/lib/libp:&quot;
SUNDIR &quot;:/usr/ccs/lib:/usr/lib&quot;;
} else if (strcmp(arg, &quot;-b&quot;) == 0)
;
else if (strncmp(arg, &quot;-ld=&quot;, 4) == 0)
ld[0] = &amp;arg[4];
else
return 0;
return 1;
}</pre>
</blockquote>
<p><code>LCCDIR</code> defaults to <code>&quot;/usr/local/lib/lcc/&quot;</code> unless
it's defined by a <code>-D</code> option as part of <code>CFLAGS</code> in the make
command, e.g.,</p>
<blockquote>
<pre>% make HOSTFILE=etc/solaris.c CFLAGS='-DLCCDIR=\&quot;/v/lib/lcc/\&quot;' lcc</pre>
</blockquote>
<p>Note the trailing slash; <code>SUNDIR</code> is provided so you can use <code>etc/solaris.c</code>
even if you have a different version of the Sun Pro compiler suite. If you're using the
gcc compiler tools instead of the Sun Pro tools, see <a HREF="../etc/gcc-solaris.c"><code>etc/gcc-solaris.c</code></a>.</p>
<p>Most of the host-specific code is platform-specific data and templates for the commands
that invoke the preprocessor, compiler, assembler, and loader. The <code>suffixes</code>
array lists the file name suffixes for C source files, preprocessed source files, assembly
language source files, object files, and executable files. <code>suffixes</code> must be
terminated with a null pointer, as shown above. The initialization of <code>suffixes</code>
in <code><a HREF="../etc/solaris.c">etc/solaris.c</a></code> are the typical ones for UNIX
systems. Each element of <code>suffixes</code> is actually a list of suffixes, separated
by semicolons; <code><a HREF="../etc/win32.c">etc/win32.c</a></code> holds an example:</p>
<blockquote>
<pre>char *suffixes[] = { &quot;.c;.C&quot;, &quot;.i;.I&quot;, &quot;.asm;.ASM;.s;.S&quot;, &quot;.obj;.OBJ&quot;, &quot;.exe&quot;, 0 };</pre>
</blockquote>
<p>When a list is given, the first suffix is used whenever lcc needs to generate a file
name. For example, with <code><a HREF="../etc/win32.c">etc/win32.c</a></code>, lcc emits
the generated assembly code into <code>.asm</code> files.</p>
<p>The <code>inputs</code> array holds a null-terminated string of directories separated
by colons or semicolons. These are used as the default value of <code>LCCINPUTS</code>, if
the environment variable <code>LCCINPUTS</code> is not set; see the <a HREF="lcc.pdf">man
page</a>.</p>
<p>Each command template is an array of pointers to strings terminated with a null
pointer; the strings are full path names of commands, arguments, or argument placeholders,
which are described below. Commands are executed in a child process, and templates can
contain multiple commands by separating commands with newlines. The driver runs each
command in a new process.</p>
<p>The <code>cpp</code> array gives the command for running lcc's preprocessor, <code>cpp</code>.
Literal arguments specified in templates, e.g., <code>&quot;-Dsparc&quot;</code> in the <code>cpp</code>
command above, are passed to the command as given.</p>
<p>The strings <code>&quot;$1&quot;</code>, <code>&quot;$2&quot;</code>, and <code>&quot;$3&quot;</code>
in templates are placeholders for <em>lists</em> of arguments that are substituted in a
copy of the template before the command is executed. <code>$1</code> is replaced by the <em>options</em>
specified by the user; for the preprocessor, this list always contains at least <code>-D__LCC__</code>.
<code>$2</code> is replaced by the <em>input</em> files, and <code>$3</code> is replaced
by the <em>output</em> file.</p>
<p>Zero-length arguments after replacement are removed from the argument list before the
command is invoked. So, for example, if the preprocessor is invoked without an output
file, <code>&quot;$3&quot;</code> becomes <code>&quot;&quot;</code>, which is removed from
the final argument list.</p>
<p>The <code>include</code> array is a list of <code>-I</code> options that specify which
directives should be searched to satisfy include directives. These directories are
searched in the order given. The first directory should be the one to which the ANSI
header files were copied as described in <a HREF="#unix">UNIX</a> or <a HREF="#win32">Windows</a>
installation instructions. The driver adds these options to <code>cpp</code>'s arguments
when it invokes the preprocessor, except when <code>-N</code> is specified.</p>
<p><code>com</code> gives the command for invoking the compiler. This template can appear
as shown above in a custom host-specific part, but the option <code>-target=sparc/solaris</code>
should be edited to the <em>target</em><code>/</code><em>os</em> for your platform. If <code>com[1]</code>
includes the string &quot;<code>win32</code>&quot;, the driver assumes it's running on
Windows. lcc can generate code for <em>all</em> of the <em>target</em><code>/</code><em>os</em>
combinations listed in the file <code>src/bind.c</code>. The <code>-target</code> option
specifies the default combination. The driver's <code>-Wf</code> option can be used to
specify other combinations; the <a HREF="lcc.pdf">man page</a> elaborates.</p>
<p><code>as</code> gives the command for invoking the assembler. On Linux, you must be
running at least version 2.8.1 of the GNU assembler; earlier versions mis-assemble some
instructions emitted by lcc.</p>
<p><code>ld</code> gives the command for invoking the loader. For the other commands, the
list <code>$2</code> contains a single file; for <code>ld</code>, <code>$2</code> contains
all &quot;.o&quot; files and libraries, and <code>$3</code> is <code>a.out</code>, unless
the <code>-o</code> option is specified. As suggested in the code above, <code>ld</code>
must also specify the appropriate startup code and default libraries, including the lcc
library, <code>liblcc.a</code>.</p>
<p>The <code>option</code> function is described below; the minimal <code>option</code>
function just returns 0.</p>
<p>You can test <code>lcc</code> with the options <code>-v -v</code> to display the
commands that would be executed, e.g.,</p>
<blockquote>
<pre>% $BUILDDIR/lcc -v -v foo.c baz.c mylib.a -lX11
/usr/local/lib/lcc-4.1/lcc $ Id: solaris.c,v 1.10 1998/09/14 20:36:33 drh Exp $
foo.c:
/usr/local/lib/lcc/cpp -D__STDC__=1 -Dsparc -D__sparc__ -Dsun -D__sun__ -Dunix -D__LCC__ -I/usr/local/lib/lcc/include -I/usr/local/include -I/usr/include foo.c /tmp/lcc266290.i
/usr/local/lib/lcc/rcc -target=sparc/solaris -v /tmp/lcc266290.i /tmp/lcc266291.
s
/usr/ccs/bin/as -Qy -s -o /tmp/lcc266292.o /tmp/lcc266291.s
baz.c:
/usr/local/lib/lcc/cpp -D__STDC__=1 -Dsparc -D__sparc__ -Dsun -D__sun__ -Dunix -D__LCC__ -I/usr/local/lib/lcc/include -I/usr/local/include -I/usr/include baz.c /tmp/lcc266290.i
/usr/local/lib/lcc/rcc -target=sparc/solaris -v /tmp/lcc266290.i /tmp/lcc266291.s
/usr/ccs/bin/as -Qy -s -o /tmp/lcc266293.o /tmp/lcc266291.s
/usr/ccs/bin/ld -o a.out /opt/SUNWspro/SC4.2/lib/crti.o /opt/SUNWspro/SC4.2/lib/crt1.o /opt/SUNWspro/SC4.2/lib/values-xa.o /tmp/lcc266292.o /tmp/lcc266293.o mylib.a -lX11 -Y P,/opt/SUNWspro/SC4.2/lib/:/usr/ccs/lib:/usr/lib -Qy -L/usr/local/lib/lcc/ -llcc -lm -lc /opt/SUNWspro/SC4.2/lib/crtn.o
rm /tmp/lcc266293.o /tmp/lcc266290.i /tmp/lcc266291.s /tmp/lcc266292.o</pre>
</blockquote>
<p>As the output shows, <code>lcc</code> places temporary files in <code>/tmp</code>; if
any of the environment variables <code>TMP</code>, <code>TEMP</code>, and <code>TMPDIR</code>
are set, they override this default (in the order shown) as does the <code>-tempdir=</code><em>dir</em>
option. The default can be changed by defining <code>TEMPDIR</code> in <code>CFLAGS</code>
when building the driver.</p>
<p>The <code>option</code> function is called for the options <code>-Wo</code>, <code>-g</code>,
<code>-p</code>, <code>-pg</code>, and <code>-b</code> because these compiler options
might also affect the loader's arguments. For these options, the driver calls <code>option(arg)</code>
to give the host-specific code an opportunity to edit the <code>ld</code> command, if
necessary. <code>option</code> can change <code>ld</code>, if necessary, and return 1 to
announce its acceptance of the option. If the option is unsupported, <code>option</code>
should return 0.</p>
<p>For example, in response to <code>-g</code>, the <code>option</code> function shown
above accepts the option but does nothing else, because the <code>ld</code> and <code>as</code>
commands don't need to be modified on the SPARC. <code>-g</code> will also be added to the
compiler's options by the host-independent part of the driver. The <code>-p</code> causes <code>option</code>
to change the name of the startup code and changed the list of libraries. The <code>-b</code>
option turns on <code>lcc</code>'s per-expression profiling, the code for which is in <code>liblcc.a</code>,
so <code>option</code> need no nothing.</p>
<p>On SPARCs, the driver also recognizes <code>-Bstatic</code> and <code>-Bdynamic</code>
as linker options. The driver recognizes but ignores &quot;<code>-target</code> <em>name</em>&quot;
option.</p>
<p>The option <code>-Wo</code><em>arg</em> causes the driver to pass <em>arg</em> to <code>option</code>.
Such options have no other effect; this mechanism is provided to support system-specific
options that affect the commands executed by the driver. As illustrated above,
host-specific parts should support the <code>-Wo-lccdir=</code><em>dir</em> option, which
causes lcc's compilation components to be found in <em>dir</em>, because this option is
used by the test scripts, and because the driver simulates a <code>-Wo-lccdir</code>
option with the value of the environment variable <code>LCCDIR</code>, if it's defined.
The code above rebuilds the paths to the include files, preprocessor, compiler, and
library by calling <code>concat</code>, which is defined in <code>etc/lcc.c</code>.</p>
<h2><a NAME="rcc">Building the Compiler and Accessories</a></h2>
<p>To build the rest of compilation components make sure <code>BUILDDIR</code> is set
appropriately and type &quot;<code>make all</code>&quot;. This command builds <code>librcc.a</code>
(the compiler's private library), <code>rcc</code> (the compiler proper), <code>lburg</code>
(the code-generator generator), <code>cpp</code> (the preprocessor), <code>liblcc.a</code>
(the runtime library), and <code>bprint</code> (the profile printer), all in <code>BUILDDIR</code>.
There may be warnings, but there should be no errors. If you're using an ANSI/ISO compiler
other than <code>cc</code>, specify its name with the <code>CC=</code> option, e.g.,
&quot;<code>make CC=gcc all</code>&quot;. If you're running on a DEC ALPHA, use &quot;<code>make
CC='cc -std1' all</code>&quot;; the <code>-std1</code> option is essential on the ALPHA.
If you're on a DEC 5000 running Ultrix 4.3, use &quot;<code>make CC=c89 all</code>&quot;.</p>
<p>Once <code>rcc</code> is built with the host C compiler, run the test suite to verify
that <code>rcc</code> is working correctly. If any of the steps below fail, contact us
(see <a HREF="#bugs"><em>Reporting Bugs</em></a>). The commands in the makefile run the
shell script <code>src/run.sh</code> on each C program in the test suite, <code>tst/*.c</code>.
It uses the driver, <code>$BUILDDIR/lcc</code>, so you must have the driver in the build
directory before testing <code>rcc</code>. The <em>target</em><code>/</code><em>os</em>
combination is read from the variable <code>TARGET</code>, which must be specified when
invoking <code>make</code>:</p>
<blockquote>
<pre>% make TARGET=sparc/solaris test
mkdir -p /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/8q.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/array.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/cf.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/cq.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/cvt.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/fields.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/front.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/incr.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/init.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/limits.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/paranoia.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/sort.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/spill.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/stdarg.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/struct.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/switch.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/wf1.s:
/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/yacc.s:</pre>
</blockquote>
<p>Each line in the output above is of the form</p>
<blockquote>
<p><code>$BUILDDIR/rcc -target=</code><em>target</em><code>/</code><em>os</em><code>$BUILDDIR/</code><em>target</em><code>/</code><em>os</em><code>/</code><em>X</em><code>.s:</code></p>
</blockquote>
<p>where <em>X</em> is the base name of the C program <em>X</em><code>.c</code> in the
test suite. This output identifies the compiler and the target, e.g., &quot;<code>$BUILDDIR/rcc</code>
is generating code for a <code>sparc</code> running the <code>solaris</code> operating
system.&quot;</p>
<p>For each program in the test suite, <code>src/run.sh</code> compiles the program, drops
the generated assembly language code in <code>BUILDDIR</code>/<em>target</em><code>/</code><em>os</em>,
and uses <code>diff</code> to compare the generated assembly code with the expected code
(the code expected for <code>tst/8q.c</code> on the SPARC under Solaris is in <code>sparc/solaris/tst/8q.sbk</code>,
etc.). If there are differences, the script executes the generated code with the input
given in <code>tst</code> (the input for <code>tst/8q.c</code> is in <code>tst/8q.0</code>,
etc.) and compares the output with the expected output (the expected output from <code>tst/8q.c</code>
on the SPARC under Solaris is in <code>sparc/solaris/tst/8q.1bk</code>, etc.). The script
also compares the diagnostics from the compiler with the expected diagnostics.</p>
<p>On some systems, there may be a few differences between the generated code and the
expected code. These differences occur because the expected code is generated by cross
compilation and the least significant bits of some floating-point constants differ from
those bits in constants generated on your system. On Linux, there may be differences
because of differences in the header files between our system and yours. There should be
no differences in the output from executing the test programs.</p>
<p>Next, run the &quot;triple test&quot;, which builds <code>rcc</code> using itself:</p>
<blockquote>
<pre>% make triple
/usr/local/lib/lcc-4.1/sparc-solaris/lcc -o /usr/local/lib/lcc-4.1/sparc-solaris/1rcc -d0.6 -Wo-lccdir=/usr/local/lib/lcc-4.1/sparc-solaris -B/usr/local/lib/lcc-4.1/sparc-solaris/ -Isrc src/*.c
src/alloc.c:
...
src/x86.c:
/usr/local/lib/lcc-4.1/sparc-solaris/lcc -o /usr/local/lib/lcc-4.1/sparc-solaris/1rcc -d0.6 -Wo-lccdir=/usr/local/lib/lcc-4.1/sparc-solaris -B/usr/local/lib/lcc-4.1/sparc-solaris/ -Isrc src/*.c
src/alloc.c:
...
src/x86.c:
strip /usr/local/lib/lcc-4.1/sparc-solaris/[12]rcc
dd if=/usr/local/lib/lcc-4.1/sparc-solaris/1rcc of=/usr/local/lib/lcc-4.1/sparc-solaris/rcc1 bs=512 skip=1
769+1 records in
769+1 records out
dd if=/usr/local/lib/lcc-4.1/sparc-solaris/2rcc of=/usr/local/lib/lcc-4.1/sparc-solaris/rcc2 bs=512 skip=1
769+1 records in
769+1 records out
if cmp /usr/local/lib/lcc-4.1/sparc-solaris/rcc[12]; then \
mv /usr/local/lib/lcc-4.1/sparc-solaris/2rcc /usr/local/lib/lcc-4.1/sparc-solaris/rcc; \
rm -f /usr/local/lib/lcc-4.1/sparc-solaris/1rcc /usr/local/lib/lcc-4.1/sparc-solaris/rcc[12]; fi</pre>
</blockquote>
<p>This command builds <code>rcc</code> twice; once using the <code>rcc</code> built by <code>cc</code>
and again using the <code>rcc</code> built by <code>lcc</code>. The resulting binaries are
compared. They should be identical, as shown at the end of the output above. If they
aren't, our compiler is generating incorrect code; <a HREF="#bugs">contact</a> us.</p>
<p>The final version of <code>rcc</code> should also pass the test suite; that is, the
output from</p>
<blockquote>
<pre>% make TARGET=sparc/solaris test</pre>
</blockquote>
<p>should be identical to that from the previous <code>make test</code>.</p>
<p>The command &quot;<code>make clean</code>&quot; cleans up, but does not remove <code>rcc</code>,
etc., and &quot;<code>make clobber</code>&quot; cleans up and removes <code>lcc</code>, <code>rcc</code>,
and the other accessories. Test directories under <code>BUILDDIR</code> are <em>not</em>
removed; you'll need to remove these by hand, e.g.,</p>
<blockquote>
<pre>% rm -fr $BUILDDIR/sparc</pre>
</blockquote>
<p>The code generators for the other targets can be tested by specifying the desired <em>target</em><code>/</code><em>os</em>
and setting an environment variable that controls what <code>src/run.sh</code> does. For
example, to test the MIPS code generator, type</p>
<blockquote>
<pre>% setenv REMOTEHOST noexecute
% make TARGET=mips/irix test</pre>
</blockquote>
<p>As above, <code>src/run.sh</code> compares the MIPS code generated with what's
expected. There should be no differences. Setting <code>REMOTEHOST</code> to <code>noexecute</code>
suppresses the assembly and execution of the generated code. If you set <code>REMOTEHOST</code>
to the name of a MIPS machine to which you can <code>rlogin</code>, <code>src/run.sh</code>
will <code>rcp</code> the generated code to that machine and execute it there, if
necessary. See <code>src/run.sh</code> for the details.</p>
<p>You can use lcc as a cross compiler. The options <code>-S</code> and <code>-Wf-target=</code><em>target/os</em>
generate assembly code for the specified target, which is any of those listed in the file <code>src/bind.c</code>.
For example, </p>
<blockquote>
<pre>% lcc -Wf-target=mips/irix -S tst/8q.c</pre>
</blockquote>
<p>generates MIPS code for <code>tst/8q.c</code> in <code>8q.s</code>.</p>
<p>lcc can also generate code for a &quot;symbolic&quot; target. This target is used
routinely in front-end development, and its output is a printable representation of the
input program, e.g., the dags constructed by the front end are printed, and other
interface functions print their arguments. You can specify this target with the option <code>-Wf-target=symbolic</code>.
For example,</p>
<blockquote>
<pre>% lcc -Wf-target=symbolic -S tst/8q.c</pre>
</blockquote>
<p>generates symbolic output for <code>tst/8q.c</code> in <code>8q.s</code>. Adding <code>-Wf-html</code>
causes the symbolic target to emit HTML instead of plain text. Finally, the option <code>-Wf-target=null</code>
specifies the &quot;null&quot; target for which lcc emits nothing and thus only checks the
syntax and semantics of its input files.</p>
<h2><a NAME="win32">Installation on Windows NT 4.0 or Windows 95/98</a></h2>
<p>On Windows NT 4.0 and Windows 95/98, lcc is designed to work with Microsoft's Visual
C++ 5.0 (VC) and Microsoft's Assembler, MASM 6.11d. It uses the VC header files,
libraries, and command-line tools, and it uses MASM to assemble the code it generates. If
you have MASM 6.11, make sure you <a
HREF="http://support.microsoft.com/support/kb/articles/Q138/9/83.asp">upgrade to 6.11d</a>,
because earlier 6.11 releases do not generate correct COFF object files.</p>
<p>Building the distribution components from the ground up requires Microsoft's Visual
C/C++ 5.0 compiler, Microsoft's make, <code>nmake</code>, and the standard Windows command
interpreter. <a HREF="../makefile.nt"><code>makefile.nt</code></a> is written to use only <code>nmake</code>.
As on UNIX systems, the compilation components are installed in a single <em>build
directory</em>, and the top-level programs, <code>lcc.exe</code> and <code>bprint.exe</code>,
are installed in a directory on the PATH. If the conventions used below are followed, the
Windows-specific parts of the driver program, <code>lcc.exe</code>, can be used
unmodified.</p>
<p>Building from the source distribution on a Windows system involves the following steps.
Below, the build directory is referred to as <code>BUILDDIR</code>, and the distribution
is in <code>\dist\lcc\4.1</code>.
<ol>
<li>Create the build directory, perhaps using a version- and platform-specific naming
convention as suggested in <a HREF="#unix"><em>Installation on UNIX</em></a>, and record
the name of this directory in the <code>BUILDDIR</code> environment variable:<blockquote>
<pre>C:\dist\lcc\4.1&gt;set BUILDDIR=\progra~1\lcc\4.1\bin
C:\dist\lcc\4.1&gt;mkdir %BUILDDIR%</pre>
</blockquote>
<p>The default build, or installation, directory is <code>\Program Files\lcc\4.1\bin</code>,
but the <code>nmake</code> commands require that you use the corresponding 8.3 file name, <code>progra~1</code>,
instead of <code>Program Files</code>.</p>
</li>
<li><a HREF="../etc/win32.c"><code>etc\win32.c</code></a> is the Windows-specific part of
the driver. It assumes that environment variable <code>include</code> gives the locations
of the VC header files and that the linker (<code>link.exe</code>) and the assembler (<code>ml.exe</code>)
are on the PATH. It also assumes that the macro <code>LCCDIR</code> gives the build
directory. If necessary, revise a copy of <a HREF="../etc/win32.c"><code>etc\win32.c</code></a>
to reflect the conventions on your computer (see <a HREF="#driver"><em>Building the Driver</em></a>),
then build the driver, specifying the default temporary directory, if necessary:<blockquote>
<pre>C:\dist\lcc\4.1&gt;nmake -f makefile.nt TEMPDIR=\\temp HOSTFILE=etc/win32.c lcc
...
cl -nologo -Zi -MLd -Fd\progra~1\lcc\4.1\bin\ -c -DTEMPDIR=\&quot;\\temp\&quot; -Fo\progra~1\lcc\4.1\bin\lcc.obj etc/lcc.c
lcc.c
cl -nologo -Zi -MLd -Fd\progra~1\lcc\4.1\bin\ -c -Fo\progra~1\lcc\4.1\bin\host.obj etc/win32.c
win32.c
cl -nologo -Zi -MLd -Fd\progra~1\lcc\4.1\bin\ -Fe\progra~1\lcc\4.1\bin\lcc.exe \progra~1\lcc\4.1\bin\lcc.obj \progra~1\lcc\4.1\bin\host.obj</pre>
</blockquote>
<p>If you make a copy of <code>etc\win32.c</code>, specify the path of the copy as the
value of <code>HOSTFILE</code>. For example, if you copy <code>etc\win32.c</code> to <code>BUILDDIR</code>
and edit it, use the command</p>
<blockquote>
<pre>C:\dist\lcc\4.1&gt;nmake -f makefile.nt TEMPDIR=\\temp HOSTFILE=%BUILDDIR%\win32.c lcc</pre>
</blockquote>
</li>
<li>Build the preprocessor, compiler proper, library, and other accessories (see <a
HREF="#rcc"><em>Building the Compiler</em></a>):<blockquote>
<pre>C:\dist\lcc\4.1&gt;nmake -f makefile.nt all</pre>
</blockquote>
<p>This command uses the VC command-line tools <code>cl</code> and <code>lib</code> to
build <code>bprint.exe</code>, <code>cpp.exe</code>, <code>lburg.exe</code>, <code>liblcc.lib</code>,
<code>librcc.lib</code>, and <code>rcc.exe</code>, all in <code>BUILDDIR</code>. There may
be some warnings, but there should be no warnings.</p>
</li>
<li>Create a test directory and run the test suite:<blockquote>
<pre>C:\dist\lcc\4.1&gt;mkdir %BUILDDIR%\x86\win32\tst
C:\dist\lcc\4.1&gt;nmake -f makefile.nt test</pre>
</blockquote>
<p>This command compiles each program in <a HREF="../tst">tst</a>, compares the generated
assembly code and diagnostics with the expected assembly code and diagnostics, executes
the program, and compares the output with the expected output (using <code>fc</code>). For
example, when the nmake command compiles <a HREF="../tst/8q.c"><code>tst\8q.c</code></a>,
it leaves the generated assembly code and diagnostic output in <code>%BUILDDIR%\x86\win32\tst\8q.s</code>
and <code>%BUILDDIR%\x86\win32\tst\8q.2</code>, and it compares them with the expected
results in <code>x86\win32\tst\8q.sbk</code>. It builds the executable program in <code>%BUILDDIR%\x86\win32\tst\8q.exe</code>,
runs it, and redirects the output to <code>%BUILDDIR%\x86\win32\tst\8q.1</code>, which it
compares with <code>x86\win32\tst\8q.1bk</code>. The output from this step is voluminous,
but there should be no differences and no errors.</p>
</li>
<li>Run the &quot;triple&quot; test, which compiles <code>rcc</code> with itself and
verifies the results:<blockquote>
<pre>C:\dist\lcc\4.1&gt;nmake -f makefile.nt triple
...
\progra~1\lcc\4.1\bin\x86.c:
Assembling: C:/TEMP/lcc2001.asm
fc /b \progra~1\lcc\4.1\bin\1rcc.exe \progra~1\lcc\4.1\bin\2rcc.exe
Comparing files \progra~1\lcc\4.1\bin\1rcc.exe and \progra~1\lcc\4.1\bin\2RCC.EXE
00000088: B4 D5</pre>
</blockquote>
<p>This command builds <code>rcc</code> twice; once using the <code>rcc</code> built by VC
and again using the <code>rcc</code> built by <code>lcc</code>. The resulting binaries are
compared using <code>fc</code>. They should be identical, except for one or two bytes of
timestamp data, as shown at the end of the output above. If they aren't, our compiler is
generating incorrect code; <a HREF="#bugs">contact</a> us.</p>
</li>
<li>Copy <code>lcc.exe</code> and <code>bprint.exe</code> to a directory on your PATH, e.g.,<blockquote>
<pre>C:\dist\lcc\4.1&gt;copy %BUILDDIR%\lcc.exe \bin
1 file(s) copied.
C:\dist\lcc\4.1&gt;copy %BUILDDIR%\bprint.exe \bin
1 file(s) copied.</pre>
</blockquote>
</li>
<li>Finally, clean up:<blockquote>
<pre>C:\dist\lcc\4.1&gt;nmake -f makefile.nt clean</pre>
</blockquote>
<p>This command removes the derived files in <code>BUILDDIR</code>, but does not remove <code>rcc.exe</code>,
etc.; &quot;<code>nmake -f makefile.nt clobber</code>&quot; cleans up and removes all
executables and libraries. Test directories under <code>BUILDDIR</code> are <em>not</em>
removed; you'll need to remove these by hand, e.g.,</p>
<blockquote>
<pre>C:\dist\lcc\4.1&gt;rmdir %BUILDDIR%\x86 /s
\progra~1\lcc\4.1\bin\x86, Are you sure (Y/N)? y</pre>
</blockquote>
</li>
</ol>
<h2><a NAME="bugs">Reporting Bugs</a></h2>
<p>lcc is a large, complex program. We find and repair errors routinely. If you think that
you've found an error, follow the steps below, which are adapted from the instructions in
Chapter 1 of <cite>A Retargetable C Compiler: Design and Implementation</cite>.
<ol>
<li>If you don't have a source file that displays the error, create one. Most errors are
exposed when programmers try to compile a program they think is valid, so you probably
have a demonstration program already.</li>
<li>Preprocess the source file and capture the preprocessor output. Discard the original
code.</li>
<li>Prune your source code until it can be pruned no more without sending the error into
hiding. We prune most error demonstrations to fewer than five lines.</li>
<li>Confirm that the source file displays the error with the <em>distributed</em> version of
lcc. If you've changed lcc and the error appears only in your version, then you'll have to
chase the error yourself, even if it turns out to be our fault, because we can't work on
your code.</li>
<li>Annotate your code with comments that explain why you think that lcc is wrong. If lcc
dies with an assertion failure, please tell us where it died. If lcc crashes, please
report the last part of the call chain if you can. If lcc is rejecting a program you think
is valid, please tell us why you think it's valid, and include supporting page numbers in
the ANSI Standard, Appendix A in <cite>The C Programming Language</cite>, or the
appropriate section in <cite>C: A Reference Manual</cite>, 4th edition by S. B. Harbison
and G. L. Steele, Jr. (Prentice Hall, 1995). If lcc silently generates incorrect code for
some construct, please include the corrupt assembly code in the comments and flag the
incorrect instructions if you can.</li>
<li>Confirm that your error hasn't been fixed already. The latest version of lcc is always
available for anonymous <code>ftp</code> from <code>ftp.cs.princeton.edu</code> in <a
HREF="ftp://ftp.cs.princeton.edu/pub/lcc"><code>pub/lcc</code></a>. A <a
HREF="ftp://ftp.cs.princeton.edu/pub/lcc/README"><code>README</code></a> file there gives
acquistion details, and the <a HREF="../LOG"><code>LOG</code></a> file reports what errors
were fixed and when they were fixed. If you report an error that's been fixed, you might
get a canned reply.</li>
<li>Send your program by electronic mail to <code>lcc-bugs@cs.princeton.edu</code>. Please
send only valid C programs; put all remarks in C comments so that we can process reports
semiautomatically.</li>
</ol>
<h2><a NAME="mailinglist">Keeping in Touch</a></h2>
<p>There is an lcc mailing list for general information about lcc. To be added to the
list, send a message with the 1-line body</p>
<blockquote>
<pre>subscribe lcc</pre>
</blockquote>
<p>to <code>majordomo@cs.princeton.edu</code>. This line must appear in the message body;
&quot;Subject:&quot; lines are ignored. To learn more about mailing lists served by <code>majordomo</code>,
send a message with the 1-word body &quot;<code>help</code>&quot; to <code>majordomo@cs.princeton.edu</code>.
Mail sent to <code>lcc@cs.princeton.edu</code> is forwarded to everyone on the mailing
list.</p>
<p>There is also an <code>lcc-bugs</code> mailing list for reporting bugs; subscribe to it
by sending a message with the 1-line body </p>
<blockquote>
<pre>subscribe lcc-bugs</pre>
</blockquote>
<p>to <code>majordomo@cs.princeton.edu</code>. Mail addressed to <var>lcc-bugs@cs.princeton.edu</var>
is forwarded to everyone on this list.</p>
<hr>
<address>
<a HREF="http://www.research.microsoft.com/~cwfraser/">Chris Fraser</a> / <a
HREF="mailto:cwfraser@microsoft.com">cwfraser@microsoft.com</a><br>
<a HREF="http://www.research.microsoft.com/~drh/">David Hanson</a> / <a
HREF="mailto:drh@microsoft.com">drh@microsoft.com</a><br>
$Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $
</address>
</body>
</html>

View File

@@ -1,605 +0,0 @@
.\" $Id: lcc.1 145 2001-10-17 21:53:10Z timo $
.TH LCC 1 "local \- $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $"
.SH NAME
lcc \- ANSI C compiler
.SH SYNOPSIS
.B lcc
[
.I option
|
.I file
]...
.br
.SH DESCRIPTION
.PP
.I lcc
is an ANSI C compiler for a variety of platforms.
.PP
Arguments whose names end with `.c' (plus `.C' under Windows) are taken to be
C source programs; they are preprocessed, compiled, and
each object program is left on the file
whose name is that of the source with `.o' (UNIX) or `.obj' (Windows)
substituted for the extension.
Arguments whose names end with `.i' are treated similarly,
except they are not preprocessed.
In the same way,
arguments ending with `.s' (plus `.S', `.asm', and `.ASM', under Windows)
are taken to be assembly source programs
and are assembled, producing an object file.
If there are no arguments,
.I lcc
summarizes its options on the standard error.
.PP
.I lcc
deletes an object file if and only if exactly one
source file is mentioned and no other file
(source, object, library) or
.B \-l
option is mentioned.
.PP
If the environment variable
.B LCCINPUTS
is set,
.I lcc
assumes it gives a semicolon- or colon-separated list of directories in which to
look for source and object files whose names do not begin with `/'.
These directories are also added to the list of directories
searched for libraries.
If
.B LCCINPUTS
is defined, it must contain `.' in order for the current directory
to be searched for input files.
.PP
.I lcc
uses ANSI standard header files (see `FILES' below).
Include files not found in the ANSI header files
are taken from the normal default include areas,
which usually includes
.BR /usr/include .
Under Windows, if the environment variable
.B include
is defined, it gives a semicolon-separated list of directories in which to search for
header files.
.PP
.I lcc
interprets the following options; unrecognized options are
taken as loader options (see
.IR ld (1))
unless
.BR \-c ,
.BR \-S ,
or
.B \-E
precedes them.
Except for
.BR \-l ,
all options are processed before any of the files
and apply to all of the files.
Applicable options are passed to each compilation phase in the order given.
.TP
.B \-c
Suppress the loading phase of the compilation, and force
an object file to be produced even if only one program is compiled.
.TP
.B \-g
Produce additional symbol table information for the local debuggers.
.I lcc
warns when
.B \-g
is unsupported.
.TP
.BI \-Wf\-g n , x
Set the debugging level to
.I n
and emit source code as comments into the generated assembly code;
.I x
must be the assembly language comment character.
If
.I n
is omitted, it defaults to 1, which is similar to
.BR \-g .
Omitting
.BI , x
just sets the debugging level to
.IR n .
.TP
.B \-w
Suppress warning diagnostics, such as those
announcing unreferenced statics, locals, and parameters.
The line
.I
#pragma ref id
simulates a reference to the variable
.IR id .
.TP
.BI \-d n
Generate jump tables for switches whose density is at least
.IR n ,
a floating point constant between zero and one.
The default is 0.5.
.TP
.B \-A
Warns about
declarations and casts of function types without prototypes,
assignments between pointers to ints and pointers to enums, and
conversions from pointers to smaller integral types.
A second
.B \-A
warns about
unrecognized control lines,
nonANSI language extensions and source characters in literals,
unreferenced variables and static functions,
declaring arrays of incomplete types,
and exceeding
.I some
ANSI environmental limits, like more than 257 cases in switches.
It also arranges for duplicate global definitions in separately compiled
files to cause loader errors.
.TP
.B \-P
Writes declarations for all defined globals on standard error.
Function declarations include prototypes;
editing this output can simplify conversion to ANSI C.
This output may not correspond to the input when
there are several typedefs for the same type.
.TP
.B \-n
Arrange for the compiler to produce code
that tests for dereferencing zero pointers.
The code reports the offending file and line number and calls
.IR abort (3).
.TP
.B \-O
is ignored.
.TP
.B \-S
Compile the named C programs, and leave the
assembler-language output on corresponding files suffixed `.s' or `.asm'.
.TP
.B \-E
Run only the preprocessor on the named C programs
and unsuffixed file arguments,
and send the result to the standard output.
.TP
.BI \-o " output"
Name the output file
.IR output .
If
.B \-c
or
.B \-S
is specified and there is exactly one source file,
this option names the object or assembly file, respectively.
Otherwise, this option names the final executable
file generated by the loader, and `a.out' (UNIX) or `a.exe' (Windows) is left undisturbed.
.I lcc
warns if
.B \-o
and
.B \-c
or
.B \-S
are given with more than one source file and ignores the
.B \-o
option.
.TP
.BI \-D name=def
Define the
.I name
to the preprocessor, as if by `#define'.
If
.I =def
is omitted, the name is defined as "1".
.TP
.BI \-U name
Remove any initial definition of
.IR name .
.TP
.BI \-I dir
`#include' files
whose names do not begin with `/' are always
sought first in the directory of the
.I file
arguments, then in directories named in
.B \-I
options, then in directories on a standard list.
.TP
.B \-N
Do not search
.I any
of the standard directories for `#include' files.
Only those directories specified by subsequent explicit
.B \-I
options will be searched, in the order given.
.TP
.BI \-B str
Use the compiler
.BI "" str rcc
instead of the default version.
Note that
.I str
often requires a trailing slash.
On Sparcs only,
.B \-Bstatic
and
.BI \-Bdynamic
are passed to the loader; see
.IR ld (1).
.TP
.BI \-Wo\-lccdir= dir
Find the preprocessor, compiler proper, and include directory
in the directory
.I dir/
or
.I
dir\\.
If the environment variable
.B LCCDIR
is defined, it gives this directory.
.I lcc
warns when this option is unsupported.
.TP
.B \-Wf-unsigned_char=1
.br
.ns
.TP
.B \-Wf-unsigned_char=0
makes plain
.B char
an unsigned (1) or signed (0) type; by default,
.B char
is signed.
.TP
.B \-Wf\-wchar_t=unsigned_char
.br
.ns
.TP
.B \-Wf\-wchar_t=unsigned_short
.br
.ns
.TP
.B \-Wf\-wchar_t=unsigned_int
Makes wide characters the type indicated; by default,
wide characters are unsigned short ints, and
.B wchar_t
is a typedef for unsigned short defined in stddef.h.
The definition for
.B wchar_t
in stddef.h must correspond to the type specified.
.TP
.B \-v
Print commands as they are executed; some of the executed
programs are directed to print their version numbers.
More than one occurrence of
.B \-v
causes the commands to be printed, but
.I not
executed.
.TP
.BR \-help " or " \-?
Print a message on the standard error summarizing
.IR lcc 's
options and giving the values of the environment variables
.B LCCINPUTS
and
.BR LCCDIR ,
if they are defined.
Under Windows, the values of
.B include
and
.B lib
are also given, if they are defined.
.TP
.B \-b
Produce code that counts the number of times each expression is executed.
If loading takes place, arrange for a
.B prof.out
file to be written when the object program terminates.
A listing annotated with execution counts can then be generated with
.IR bprint (1).
.I lcc
warns when
.B \-b
is unsupported.
.B \-Wf\-C
is similar, but counts only the number of function calls.
.TP
.B \-p
Produce code that counts the number of times each function is called.
If loading takes place, replace the standard startup
function by one that automatically calls
.IR monitor (3)
at the start and arranges to write a
.B mon.out
file when the object program terminates normally.
An execution profile can then be generated with
.IR prof (1).
.I lcc
warns when
.B \-p
is unsupported.
.TP
.B \-pg
Causes the compiler to produce counting code like
.BR \-p ,
but invokes a run-time recording mechanism that keeps more
extensive statistics and produces a
.B gmon.out
file at normal termination.
Also, a profiling library is searched, in lieu of the standard C library.
An execution profile can then be generated with
.IR gprof (1).
.I lcc
warns when
.B \-pg
is unsupported.
.TP
.BI \-t name
.br
.ns
.TP
.BI \-t
Produce code to print the name of the function, an activation number,
and the name and value of each argument at function entry.
At function exit, produce code to print
the name of the function, the activation number, and the return value.
By default,
.I printf
does the printing; if
.I name
appears, it does.
For null
.I char*
values, "(null)" is printed.
.BI \-target
.I name
is accepted, but ignored.
.TP
.BI \-tempdir= dir
Store temporary files in the directory
.I dir/
or
.I
dir\\.
The default is usually
.BR /tmp .
.TP
.BI \-W xarg
pass argument
.I arg
to the program indicated by
.IR x ;
.I x
can be one of
.BR p ,
.BR f ,
.BR a ,
or
.BR l ,
which refer, respectively, to the preprocessor, the compiler proper,
the assembler, and the loader.
.I arg
is passed as given; if a
.B \-
is expected, it must be given explicitly.
.BI \-Wo arg
specifies a system-specific option,
.IR arg .
.PP
Other arguments
are taken to be either loader option arguments, or C-compatible
object programs, typically produced by an earlier
.I lcc
run, or perhaps libraries of C-compatible routines.
Duplicate object files are ignored.
These programs, together with the results of any
compilations specified, are loaded (in the order
given) to produce an executable program with name
.BR a.out
(UNIX) or
.BR a.exe
(Windows).
.PP
.I lcc
assigns the most frequently referenced scalar parameters and
locals to registers whenever possible.
For each block,
explicit register declarations are obeyed first;
remaining registers are assigned to automatic locals if they
are `referenced' at least 3 times.
Each top-level occurrence of an identifier
counts as 1 reference. Occurrences in a loop,
either of the then/else arms of an if statement, or a case
in a switch statement each count, respectively, as 10, 1/2, or 1/10 references.
These values are adjusted accordingly for nested control structures.
.B \-Wf\-a
causes
.I lcc
to read a
.B prof.out
file from a previous execution and to use the data therein
to compute reference counts (see
.BR \-b ).
.PP
.I lcc
is a cross compiler;
.BI \-Wf\-target= target/os
causes
.I lcc
to generate code for
.I target
running the operating system denoted by
.IR os .
The supported
.I target/os
combinations may include
.PP
.RS
.ta \w'sparc/solarisxx'u
.nf
alpha/osf ALPHA, OSF 3.2
mips/irix big-endian MIPS, IRIX 5.2
mips/ultrix little-endian MIPS, ULTRIX 4.3
sparc/solaris SPARC, Solaris 2.3
x86/win32 x86, Windows NT 4.0/Windows 95/98
x86/linux x86, Linux
symbolic text rendition of the generated code
null no output
.fi
.RE
.PP
For
.BR \-Wf\-target=symbolic ,
the option
.B \-Wf-html
causes the text rendition to be emitted as HTML.
.B
.SH LIMITATIONS
.PP
.I lcc
accepts the C programming language
as described in the ANSI standard.
If
.I lcc
is used with the GNU C preprocessor, the
.B \-Wp\-trigraphs
option is required to enable trigraph sequences.
.PP
Plain int bit fields are signed.
Bit fields are aligned like unsigned integers but are otherwise laid out
as by most standard C compilers.
Some compilers, such as the GNU C compiler,
may choose other, incompatible layouts.
.PP
Likewise, calling conventions are intended to be compatible with
the host C compiler,
except possibly for passing and returning structures.
Specifically,
.I lcc
passes and returns structures like host ANSI C compilers
on most targets, but some older host C compilers use different conventions.
Consequently, calls to/from such functions compiled with
older C compilers may not work.
Calling a function that returns
a structure without declaring it as such violates
the ANSI standard and may cause a fault.
.SH FILES
.PP
The file names listed below are
.IR typical ,
but vary among installations; installation-dependent variants
can be displayed by running
.I lcc
with the
.B \-v
option.
.PP
.RS
.ta \w'$LCCDIR/liblcc.{a,lib}XX'u
.nf
file.{c,C} input file
file.{s,asm} assembly-language file
file.{o,obj} object file
a.{out,exe} loaded output
/tmp/lcc* temporary files
$LCCDIR/cpp preprocessor
$LCCDIR/rcc compiler
$LCCDIR/liblcc.{a,lib} \fIlcc\fP-specific library
/lib/crt0.o runtime startup (UNIX)
/lib/[gm]crt0.o startups for profiling (UNIX)
/lib/libc.a standard library (UNIX)
$LCCDIR/include ANSI standard headers
/usr/local/include local headers
/usr/include traditional headers
prof.out file produced for \fIbprint\fR(1)
mon.out file produced for \fIprof\fR(1)
gmon.out file produced for \fIgprof\fR(1)
.fi
.RE
.PP
.I lcc
predefines the macro
.B __LCC__
on all systems.
It may also predefine some installation-dependent symbols; option
.B \-v
exposes them.
.SH "SEE ALSO"
.PP
C. W. Fraser and D. R. Hanson,
.I A Retargetable C Compiler: Design and Implementation,
Addison-Wesley, 1995. ISBN 0-8053-1670-1.
.PP
The World-Wide Web page at http://www.cs.princeton.edu/software/lcc/.
.PP
S. P. Harbison and G. L. Steele, Jr.,
.I C: A Reference Manual,
4th ed., Prentice-Hall, 1995.
.PP
B. W. Kernighan and D. M. Ritchie,
.I The C Programming Language,
2nd ed., Prentice-Hall, 1988.
.PP
American National Standards Inst.,
.I American National Standard for Information Systems\(emProgramming
.IR Language\(emC ,
ANSI X3.159-1989, New York, 1990.
.br
.SH BUGS
Mail bug reports along with the shortest preprocessed program
that exposes them and the details reported by
.IR lcc 's
.B \-v
option to lcc-bugs@princeton.edu. The WWW page at
URL http://www.cs.princeton.edu/software/lcc/
includes detailed instructions for reporting bugs.
.PP
The ANSI standard headers conform to the specifications in
the Standard, which may be too restrictive for some applications,
but necessary for portability.
Functions given in the ANSI headers may be missing from
some local C libraries (e.g., wide-character functions)
or may not correspond exactly to the local versions;
for example, the ANSI standard
stdio.h
specifies that
.IR printf ,
.IR fprintf ,
and
.I sprintf
return the number of characters written to the file or array,
but some existing libraries don't implement this convention.
.PP
On the MIPS and SPARC, old-style variadic functions must use
varargs.h
from MIPS or Sun. New-style is recommended.
.PP
With
.BR \-b ,
files compiled
.I without
.B \-b
may cause
.I bprint
to print erroneous call graphs.
For example, if
.B f
calls
.B g
calls
.B h
and
.B f
and
.B h
are compiled with
.BR \-b ,
but
.B g
is not,
.B bprint
will report that
.B f
called
.BR h .
The total number of calls is correct, however.

Binary file not shown.

View File

@@ -1,66 +0,0 @@
/* quake3 bytecode target */
#include <string.h>
#include <stdio.h>
#include "../../../qcommon/q_platform.h"
#ifdef _WIN32
#define BINEXT ".exe"
#else
#define BINEXT ""
#endif
char *suffixes[] = { ".c", ".i", ".asm", ".o", ".out", 0 };
char inputs[256] = "";
char *cpp[] = { "q3cpp" BINEXT,
"-D__STDC__=1", "-D__STRICT_ANSI__", "-D__signed__=signed", "-DQ3_VM",
"$1", "$2", "$3", 0 };
char *include[] = { 0 };
char *com[] = { "q3rcc" BINEXT, "-target=bytecode", "$1", "$2", "$3", 0 };
char *ld[] = { 0 };
char *as[] = { 0 };
extern char *concat(char *, char *);
/*
===============
UpdatePaths
Updates the paths to q3cpp and q3rcc based on
the directory that contains q3lcc
===============
*/
void UpdatePaths( const char *lccBinary )
{
char basepath[ 1024 ];
char *p;
strncpy( basepath, lccBinary, 1024 );
p = strrchr( basepath, PATH_SEP );
if( p )
{
*( p + 1 ) = '\0';
cpp[ 0 ] = concat( basepath, "q3cpp" BINEXT );
com[ 0 ] = concat( basepath, "q3rcc" BINEXT );
}
}
int option(char *arg) {
if (strncmp(arg, "-lccdir=", 8) == 0) {
cpp[0] = concat(&arg[8], "/q3cpp" BINEXT);
include[0] = concat("-I", concat(&arg[8], "/include"));
com[0] = concat(&arg[8], "/q3rcc" BINEXT);
} else if (strcmp(arg, "-p") == 0 || strcmp(arg, "-pg") == 0) {
fprintf( stderr, "no profiling supported, %s ignored.\n", arg);
} else if (strcmp(arg, "-b") == 0)
;
else if (strcmp(arg, "-g") == 0)
fprintf( stderr, "no debugging supported, %s ignored.\n", arg);
else if (strncmp(arg, "-ld=", 4) == 0 || strcmp(arg, "-static") == 0) {
fprintf( stderr, "no linking supported, %s ignored.\n", arg);
} else
return 0;
return 1;
}

View File

@@ -1,852 +0,0 @@
/*
* lcc [ option ]... [ file | -llib ]...
* front end for the ANSI C compiler
*/
static char rcsid[] = "Id: dummy rcsid";
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <signal.h>
#include <unistd.h>
#ifndef TEMPDIR
#define TEMPDIR "/tmp"
#endif
typedef struct list *List;
struct list { /* circular list nodes: */
char *str; /* option or file name */
List link; /* next list element */
};
static void *alloc(int);
static List append(char *,List);
extern char *basename(char *);
static int callsys(char *[]);
extern char *concat(char *, char *);
static int compile(char *, char *);
static void compose(char *[], List, List, List);
static void error(char *, char *);
static char *exists(char *);
static char *first(char *);
static int filename(char *, char *);
static List find(char *, List);
static void help(void);
static void initinputs(void);
static void interrupt(int);
static void opt(char *);
static List path2list(const char *);
extern int main(int, char *[]);
extern char *replace(const char *, int, int);
static void rm(List);
extern char *strsave(const char *);
extern char *stringf(const char *, ...);
extern int suffix(char *, char *[], int);
extern char *tempname(char *);
#ifndef __sun
extern int getpid(void);
#endif
extern char *cpp[], *include[], *com[], *as[],*ld[], inputs[], *suffixes[];
extern int option(char *);
static int errcnt; /* number of errors */
static int Eflag; /* -E specified */
static int Sflag = 1; /* -S specified */ //for Q3 we always generate asm
static int cflag; /* -c specified */
static int verbose; /* incremented for each -v */
static List llist[2]; /* loader files, flags */
static List alist; /* assembler flags */
static List clist; /* compiler flags */
static List plist; /* preprocessor flags */
static List ilist; /* list of additional includes from LCCINPUTS */
static List rmlist; /* list of files to remove */
static char *outfile; /* ld output file or -[cS] object file */
static int ac; /* argument count */
static char **av; /* argument vector */
char *tempdir = TEMPDIR; /* directory for temporary files */
static char *progname;
static List lccinputs; /* list of input directories */
extern void UpdatePaths( const char *lccBinary );
int main(int argc, char *argv[]) {
int i, j, nf;
progname = argv[0];
UpdatePaths( progname );
ac = argc + 50;
av = alloc(ac*sizeof(char *));
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, interrupt);
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
signal(SIGTERM, interrupt);
#ifdef SIGHUP
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
signal(SIGHUP, interrupt);
#endif
if (getenv("TMP"))
tempdir = getenv("TMP");
else if (getenv("TEMP"))
tempdir = getenv("TEMP");
else if (getenv("TMPDIR"))
tempdir = getenv("TMPDIR");
assert(tempdir);
i = strlen(tempdir);
for (; (i > 0 && tempdir[i-1] == '/') || tempdir[i-1] == '\\'; i--)
tempdir[i-1] = '\0';
if (argc <= 1) {
help();
exit(0);
}
plist = append("-D__LCC__", 0);
initinputs();
if (getenv("LCCDIR"))
option(stringf("-lccdir=%s", getenv("LCCDIR")));
for (nf = 0, i = j = 1; i < argc; i++) {
if (strcmp(argv[i], "-o") == 0) {
if (++i < argc) {
if (suffix(argv[i], suffixes, 2) >= 0) {
error("-o would overwrite %s", argv[i]);
exit(8);
}
outfile = argv[i];
continue;
} else {
error("unrecognized option `%s'", argv[i-1]);
exit(8);
}
} else if (strcmp(argv[i], "-target") == 0) {
if (argv[i+1] && *argv[i+1] != '-')
i++;
continue;
} else if (*argv[i] == '-' && argv[i][1] != 'l') {
opt(argv[i]);
continue;
} else if (*argv[i] != '-' && suffix(argv[i], suffixes, 3) >= 0)
nf++;
argv[j++] = argv[i];
}
if ((cflag || Sflag) && outfile && nf != 1) {
fprintf(stderr, "%s: -o %s ignored\n", progname, outfile);
outfile = 0;
}
argv[j] = 0;
for (i = 0; include[i]; i++)
plist = append(include[i], plist);
if (ilist) {
List b = ilist;
do {
b = b->link;
plist = append(b->str, plist);
} while (b != ilist);
}
ilist = 0;
for (i = 1; argv[i]; i++)
if (*argv[i] == '-')
opt(argv[i]);
else {
char *name = exists(argv[i]);
if (name) {
if (strcmp(name, argv[i]) != 0
|| (nf > 1 && suffix(name, suffixes, 3) >= 0))
fprintf(stderr, "%s:\n", name);
filename(name, 0);
} else
error("can't find `%s'", argv[i]);
}
if (errcnt == 0 && !Eflag && !Sflag && !cflag && llist[1]) {
compose(ld, llist[0], llist[1],
append(outfile ? outfile : concat("a", first(suffixes[4])), 0));
if (callsys(av))
errcnt++;
}
rm(rmlist);
return errcnt ? EXIT_FAILURE : EXIT_SUCCESS;
}
/* alloc - allocate n bytes or die */
static void *alloc(int n) {
static char *avail, *limit;
n = (n + sizeof(char *) - 1)&~(sizeof(char *) - 1);
if (n >= limit - avail) {
avail = malloc(n + 4*1024);
assert(avail);
limit = avail + n + 4*1024;
}
avail += n;
return avail - n;
}
/* append - append a node with string str onto list, return new list */
static List append(char *str, List list) {
List p = alloc(sizeof *p);
p->str = str;
if (list) {
p->link = list->link;
list->link = p;
} else
p->link = p;
return p;
}
/* basename - return base name for name, e.g. /usr/drh/foo.c => foo */
char *basename(char *name) {
char *s, *b, *t = 0;
for (b = s = name; *s; s++)
if (*s == '/' || *s == '\\') {
b = s + 1;
t = 0;
} else if (*s == '.')
t = s;
s = strsave(b);
if (t)
s[t-b] = 0;
return s;
}
#ifdef WIN32
#include <process.h>
static char *escapeDoubleQuotes(const char *string) {
int stringLength = strlen(string);
int bufferSize = stringLength + 1;
int i, j;
char *newString;
if (string == NULL)
return NULL;
for (i = 0; i < stringLength; i++) {
if (string[i] == '"')
bufferSize++;
}
newString = (char*)malloc(bufferSize);
if (newString == NULL)
return NULL;
for (i = 0, j = 0; i < stringLength; i++) {
if (string[i] == '"')
newString[j++] = '\\';
newString[j++] = string[i];
}
newString[j] = '\0';
return newString;
}
static int spawn(const char *cmdname, char **argv) {
int argc = 0;
char **newArgv = argv;
int i;
intptr_t exitStatus;
// _spawnvp removes double quotes from arguments, so we
// have to escape them manually
while (*newArgv++ != NULL)
argc++;
newArgv = (char **)malloc(sizeof(char*) * (argc + 1));
for (i = 0; i < argc; i++)
newArgv[i] = escapeDoubleQuotes(argv[i]);
newArgv[argc] = NULL;
exitStatus = _spawnvp(_P_WAIT, cmdname, (const char *const *)newArgv);
for (i = 0; i < argc; i++)
free(newArgv[i]);
free(newArgv);
return exitStatus;
}
#else
#define _P_WAIT 0
#ifndef __sun
extern int fork(void);
#endif
extern int wait(int *);
static int spawn(const char *cmdname, char **argv) {
int pid, n, status;
switch (pid = fork()) {
case -1:
fprintf(stderr, "%s: no more processes\n", progname);
return 100;
case 0:
// TTimo removing hardcoded paths, searching in $PATH
execvp(cmdname, argv);
fprintf(stderr, "%s: ", progname);
perror(cmdname);
fflush(stdout);
exit(100);
}
while ((n = wait(&status)) != pid && n != -1)
;
if (n == -1)
status = -1;
if (status&0377) {
fprintf(stderr, "%s: fatal error in %s\n", progname, cmdname);
status |= 0400;
}
return (status>>8)&0377;
}
#endif
/* callsys - execute the command described by av[0...], return status */
static int callsys(char **av) {
int i, status = 0;
static char **argv;
static int argc;
char *executable;
for (i = 0; av[i] != NULL; i++)
;
if (i + 1 > argc) {
argc = i + 1;
if (argv == NULL)
argv = malloc(argc*sizeof *argv);
else
argv = realloc(argv, argc*sizeof *argv);
assert(argv);
}
for (i = 0; status == 0 && av[i] != NULL; ) {
int j = 0;
char *s = NULL;
for ( ; av[i] != NULL && (s = strchr(av[i], '\n')) == NULL; i++)
argv[j++] = av[i];
if (s != NULL) {
if (s > av[i])
argv[j++] = stringf("%.*s", s - av[i], av[i]);
if (s[1] != '\0')
av[i] = s + 1;
else
i++;
}
argv[j] = NULL;
executable = strsave( argv[0] );
argv[0] = stringf( "\"%s\"", argv[0] );
if (verbose > 0) {
int k;
fprintf(stderr, "%s", argv[0]);
for (k = 1; argv[k] != NULL; k++)
fprintf(stderr, " %s", argv[k]);
fprintf(stderr, "\n");
}
if (verbose < 2)
status = spawn(executable, argv);
if (status == -1) {
fprintf(stderr, "%s: ", progname);
perror(argv[0]);
}
}
return status;
}
/* concat - return concatenation of strings s1 and s2 */
char *concat(char *s1, char *s2) {
int n = strlen(s1);
char *s = alloc(n + strlen(s2) + 1);
strcpy(s, s1);
strcpy(s + n, s2);
return s;
}
/* compile - compile src into dst, return status */
static int compile(char *src, char *dst) {
compose(com, clist, append(src, 0), append(dst, 0));
return callsys(av);
}
/* compose - compose cmd into av substituting a, b, c for $1, $2, $3, resp. */
static void compose(char *cmd[], List a, List b, List c) {
int i, j;
List lists[3];
lists[0] = a;
lists[1] = b;
lists[2] = c;
for (i = j = 0; cmd[i]; i++) {
char *s = strchr(cmd[i], '$');
if (s && isdigit(s[1])) {
int k = s[1] - '0';
assert(k >=1 && k <= 3);
if ((b = lists[k-1])) {
b = b->link;
av[j] = alloc(strlen(cmd[i]) + strlen(b->str) - 1);
strncpy(av[j], cmd[i], s - cmd[i]);
av[j][s-cmd[i]] = '\0';
strcat(av[j], b->str);
strcat(av[j++], s + 2);
while (b != lists[k-1]) {
b = b->link;
assert(j < ac);
av[j++] = b->str;
};
}
} else if (*cmd[i]) {
assert(j < ac);
av[j++] = cmd[i];
}
}
av[j] = NULL;
}
/* error - issue error msg according to fmt, bump error count */
static void error(char *fmt, char *msg) {
fprintf(stderr, "%s: ", progname);
fprintf(stderr, fmt, msg);
fprintf(stderr, "\n");
errcnt++;
}
/* exists - if `name' readable return its path name or return null */
static char *exists(char *name) {
List b;
if ( (name[0] == '/' || name[0] == '\\' || name[2] == ':')
&& access(name, 4) == 0)
return name;
if (!(name[0] == '/' || name[0] == '\\' || name[2] == ':')
&& (b = lccinputs))
do {
b = b->link;
if (b->str[0]) {
char buf[1024];
sprintf(buf, "%s/%s", b->str, name);
if (access(buf, 4) == 0)
return strsave(buf);
} else if (access(name, 4) == 0)
return name;
} while (b != lccinputs);
if (verbose > 1)
return name;
return 0;
}
/* first - return first component in semicolon separated list */
static char *first(char *list) {
char *s = strchr(list, ';');
if (s) {
char buf[1024];
strncpy(buf, list, s-list);
buf[s-list] = '\0';
return strsave(buf);
} else
return list;
}
/* filename - process file name argument `name', return status */
static int filename(char *name, char *base) {
int status = 0;
static char *stemp, *itemp;
if (base == 0)
base = basename(name);
switch (suffix(name, suffixes, 4)) {
case 0: /* C source files */
compose(cpp, plist, append(name, 0), 0);
if (Eflag) {
status = callsys(av);
break;
}
if (itemp == NULL)
itemp = tempname(first(suffixes[1]));
compose(cpp, plist, append(name, 0), append(itemp, 0));
status = callsys(av);
if (status == 0)
return filename(itemp, base);
break;
case 1: /* preprocessed source files */
if (Eflag)
break;
if (Sflag)
status = compile(name, outfile ? outfile : concat(base, first(suffixes[2])));
else if ((status = compile(name, stemp?stemp:(stemp=tempname(first(suffixes[2]))))) == 0)
return filename(stemp, base);
break;
case 2: /* assembly language files */
if (Eflag)
break;
if (!Sflag) {
char *ofile;
if (cflag && outfile)
ofile = outfile;
else if (cflag)
ofile = concat(base, first(suffixes[3]));
else
ofile = tempname(first(suffixes[3]));
compose(as, alist, append(name, 0), append(ofile, 0));
status = callsys(av);
if (!find(ofile, llist[1]))
llist[1] = append(ofile, llist[1]);
}
break;
case 3: /* object files */
if (!find(name, llist[1]))
llist[1] = append(name, llist[1]);
break;
default:
if (Eflag) {
compose(cpp, plist, append(name, 0), 0);
status = callsys(av);
}
llist[1] = append(name, llist[1]);
break;
}
if (status)
errcnt++;
return status;
}
/* find - find 1st occurrence of str in list, return list node or 0 */
static List find(char *str, List list) {
List b;
if ((b = list))
do {
if (strcmp(str, b->str) == 0)
return b;
} while ((b = b->link) != list);
return 0;
}
/* help - print help message */
static void help(void) {
static char *msgs[] = {
"", " [ option | file ]...\n",
" except for -l, options are processed left-to-right before files\n",
" unrecognized options are taken to be linker options\n",
"-A warn about nonANSI usage; 2nd -A warns more\n",
"-b emit expression-level profiling code; see bprint(1)\n",
#ifdef sparc
"-Bstatic -Bdynamic specify static or dynamic libraries\n",
#endif
"-Bdir/ use the compiler named `dir/rcc'\n",
"-c compile only\n",
"-dn set switch statement density to `n'\n",
"-Dname -Dname=def define the preprocessor symbol `name'\n",
"-E run only the preprocessor on the named C programs and unsuffixed files\n",
"-g produce symbol table information for debuggers\n",
"-help or -? print this message\n",
"-Idir add `dir' to the beginning of the list of #include directories\n",
"-lx search library `x'\n",
"-N do not search the standard directories for #include files\n",
"-n emit code to check for dereferencing zero pointers\n",
"-O is ignored\n",
"-o file leave the output in `file'\n",
"-P print ANSI-style declarations for globals\n",
"-p -pg emit profiling code; see prof(1) and gprof(1)\n",
"-S compile to assembly language\n",
#ifdef linux
"-static specify static libraries (default is dynamic)\n",
#endif
"-t -tname emit function tracing calls to printf or to `name'\n",
"-target name is ignored\n",
"-tempdir=dir place temporary files in `dir/'", "\n"
"-Uname undefine the preprocessor symbol `name'\n",
"-v show commands as they are executed; 2nd -v suppresses execution\n",
"-w suppress warnings\n",
"-Woarg specify system-specific `arg'\n",
"-W[pfal]arg pass `arg' to the preprocessor, compiler, assembler, or linker\n",
0 };
int i;
char *s;
msgs[0] = progname;
for (i = 0; msgs[i]; i++) {
fprintf(stderr, "%s", msgs[i]);
if (strncmp("-tempdir", msgs[i], 8) == 0 && tempdir)
fprintf(stderr, "; default=%s", tempdir);
}
#define xx(v) if ((s = getenv(#v))) fprintf(stderr, #v "=%s\n", s)
xx(LCCINPUTS);
xx(LCCDIR);
#undef xx
}
/* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */
static void initinputs(void) {
char *s = getenv("LCCINPUTS");
List b;
if (s == 0 || (s = inputs)[0] == 0)
s = ".";
if (s) {
lccinputs = path2list(s);
if ((b = lccinputs))
do {
b = b->link;
if (strcmp(b->str, ".") != 0) {
ilist = append(concat("-I", b->str), ilist);
if (strstr(com[1], "win32") == NULL)
llist[0] = append(concat("-L", b->str), llist[0]);
} else
b->str = "";
} while (b != lccinputs);
}
}
/* interrupt - catch interrupt signals */
static void interrupt(int n) {
rm(rmlist);
exit(n = 100);
}
/* opt - process option in arg */
static void opt(char *arg) {
switch (arg[1]) { /* multi-character options */
case 'W': /* -Wxarg */
if (arg[2] && arg[3])
switch (arg[2]) {
case 'o':
if (option(&arg[3]))
return;
break;
case 'p':
plist = append(&arg[3], plist);
return;
case 'f':
if (strcmp(&arg[3], "-C") || option("-b")) {
clist = append(&arg[3], clist);
return;
}
break; /* and fall thru */
case 'a':
alist = append(&arg[3], alist);
return;
case 'l':
llist[0] = append(&arg[3], llist[0]);
return;
}
fprintf(stderr, "%s: %s ignored\n", progname, arg);
return;
case 'd': /* -dn */
arg[1] = 's';
clist = append(arg, clist);
return;
case 't': /* -t -tname -tempdir=dir */
if (strncmp(arg, "-tempdir=", 9) == 0)
tempdir = arg + 9;
else
clist = append(arg, clist);
return;
case 'p': /* -p -pg */
if (option(arg))
clist = append(arg, clist);
else
fprintf(stderr, "%s: %s ignored\n", progname, arg);
return;
case 'D': /* -Dname -Dname=def */
case 'U': /* -Uname */
case 'I': /* -Idir */
plist = append(arg, plist);
return;
case 'B': /* -Bdir -Bstatic -Bdynamic */
#ifdef sparc
if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0)
llist[1] = append(arg, llist[1]);
else
#endif
{
static char *path;
if (path)
error("-B overwrites earlier option", 0);
path = arg + 2;
if (strstr(com[1], "win32") != NULL)
com[0] = concat(replace(path, '/', '\\'), concat("rcc", first(suffixes[4])));
else
com[0] = concat(path, "rcc");
if (path[0] == 0)
error("missing directory in -B option", 0);
}
return;
case 'h':
if (strcmp(arg, "-help") == 0) {
static int printed = 0;
case '?':
if (!printed)
help();
printed = 1;
return;
}
#ifdef linux
case 's':
if (strcmp(arg,"-static") == 0) {
if (!option(arg))
fprintf(stderr, "%s: %s ignored\n", progname, arg);
return;
}
#endif
}
if (arg[2] == 0)
switch (arg[1]) { /* single-character options */
case 'S':
Sflag++;
return;
case 'O':
fprintf(stderr, "%s: %s ignored\n", progname, arg);
return;
case 'A': case 'n': case 'w': case 'P':
clist = append(arg, clist);
return;
case 'g': case 'b':
if (option(arg))
clist = append(arg[1] == 'g' ? "-g2" : arg, clist);
else
fprintf(stderr, "%s: %s ignored\n", progname, arg);
return;
case 'G':
if (option(arg)) {
clist = append("-g3", clist);
llist[0] = append("-N", llist[0]);
} else
fprintf(stderr, "%s: %s ignored\n", progname, arg);
return;
case 'E':
Eflag++;
return;
case 'c':
cflag++;
return;
case 'N':
if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
plist = append("-nostdinc", plist);
include[0] = 0;
ilist = 0;
return;
case 'v':
if (verbose++ == 0) {
if (strcmp(basename(cpp[0]), "gcc-cpp") == 0)
plist = append(arg, plist);
clist = append(arg, clist);
fprintf(stderr, "%s %s\n", progname, rcsid);
}
return;
}
if (cflag || Sflag || Eflag)
fprintf(stderr, "%s: %s ignored\n", progname, arg);
else
llist[1] = append(arg, llist[1]);
}
/* path2list - convert a colon- or semicolon-separated list to a list */
static List path2list(const char *path) {
List list = NULL;
char sep = ':';
if (path == NULL)
return NULL;
if (strchr(path, ';'))
sep = ';';
while (*path) {
char *p, buf[512];
if ((p = strchr(path, sep))) {
assert(p - path < sizeof buf);
strncpy(buf, path, p - path);
buf[p-path] = '\0';
} else {
assert(strlen(path) < sizeof buf);
strcpy(buf, path);
}
if (!find(buf, list))
list = append(strsave(buf), list);
if (p == 0)
break;
path = p + 1;
}
return list;
}
/* replace - copy str, then replace occurrences of from with to, return the copy */
char *replace(const char *str, int from, int to) {
char *s = strsave(str), *p = s;
for ( ; (p = strchr(p, from)) != NULL; p++)
*p = to;
return s;
}
/* rm - remove files in list */
static void rm(List list) {
if (list) {
List b = list;
if (verbose)
fprintf(stderr, "rm");
do {
if (verbose)
fprintf(stderr, " %s", b->str);
if (verbose < 2)
remove(b->str);
} while ((b = b->link) != list);
if (verbose)
fprintf(stderr, "\n");
}
}
/* strsave - return a saved copy of string str */
char *strsave(const char *str) {
return strcpy(alloc(strlen(str)+1), str);
}
/* stringf - format and return a string */
char *stringf(const char *fmt, ...) {
char buf[1024];
va_list ap;
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
return strsave(buf);
}
/* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */
int suffix(char *name, char *tails[], int n) {
int i, len = strlen(name);
for (i = 0; i < n; i++) {
char *s = tails[i], *t;
for ( ; (t = strchr(s, ';')); s = t + 1) {
int m = t - s;
if (len > m && strncmp(&name[len-m], s, m) == 0)
return i;
}
if (*s) {
int m = strlen(s);
if (len > m && strncmp(&name[len-m], s, m) == 0)
return i;
}
}
return -1;
}
/* tempname - generate a temporary file name in tempdir with given suffix */
char *tempname(char *suffix) {
static int n;
char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix);
if (strstr(com[1], "win32") != NULL)
name = replace(name, '/', '\\');
rmlist = append(name, rmlist);
return name;
}

View File

@@ -1,680 +0,0 @@
#if defined(__STDC__) || defined(__cplusplus)
#define YYCONST const
#define YYPARAMS(x) x
#define YYDEFUN(name, arglist, args) name(args)
#define YYAND ,
#define YYPTR void *
#else
#define YYCONST
#define YYPARAMS(x) ()
#define YYDEFUN(name, arglist, args) name arglist args;
#define YYAND ;
#define YYPTR char *
#endif
#ifndef lint
YYCONST static char yysccsid[] = "@(#)yaccpar 1.8 (Berkeley +Cygnus.28) 01/20/91";
#endif
#define YYBYACC 1
#ifndef YYDONT_INCLUDE_STDIO
#include <stdio.h>
#endif
#include <stdlib.h> /* for malloc/realloc/free */
#line 2 "lburg/gram.y"
#include <stdio.h>
#include "lburg.h"
/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */
static int yylineno = 0;
#line 8 "lburg/gram.y"
typedef union {
int n;
char *string;
Tree tree;
} YYSTYPE;
#line 37 "y.tab.c"
#define TERMINAL 257
#define START 258
#define PPERCENT 259
#define ID 260
#define TEMPLATE 261
#define CODE 262
#define INT 263
#define YYERRCODE 256
static YYCONST short yylhs[] = { -1,
0, 0, 4, 4, 6, 6, 6, 6, 7, 7,
5, 5, 5, 5, 1, 3, 3, 3, 2,
};
static YYCONST short yylen[] = { 2,
3, 1, 0, 2, 3, 3, 1, 2, 0, 4,
0, 7, 2, 3, 1, 1, 4, 6, 1,
};
static YYCONST short yydefred[] = { 3,
0, 0, 0, 9, 0, 11, 7, 4, 8, 0,
15, 0, 0, 0, 5, 6, 0, 13, 0, 0,
14, 0, 10, 0, 0, 0, 0, 0, 19, 0,
17, 0, 12, 0, 18,
};
static YYCONST short yydgoto[] = { 1,
12, 30, 25, 2, 13, 8, 10,
};
static YYCONST short yysindex[] = { 0,
0, -4, -2, 0, -250, 0, 0, 0, 0, -9,
0, 1, -10, -49, 0, 0, 3, 0, -44, -248,
0, -244, 0, -22, -242, -244, -245, -37, 0, 10,
0, -244, 0, -20, 0,
};
static YYCONST short yyrindex[] = { 0,
0, 22, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 23, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, -39, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
};
static YYCONST short yygindex[] = { 0,
11, 0, -23, 0, 0, 0, 0,
};
#define YYTABLESIZE 255
static YYCONST short yytable[] = { 18,
15, 16, 28, 31, 16, 7, 32, 9, 34, 11,
16, 20, 21, 22, 23, 24, 29, 26, 27, 33,
35, 2, 1, 19, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 17, 0, 0, 0, 11,
14, 3, 4, 5, 6,
};
static YYCONST short yycheck[] = { 10,
10, 41, 26, 41, 44, 10, 44, 10, 32, 260,
10, 61, 10, 58, 263, 260, 262, 40, 261, 10,
41, 0, 0, 13, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 261, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, 256, -1, -1, -1, 260,
260, 256, 257, 258, 259,
};
#define YYFINAL 1
#ifndef YYDEBUG
#define YYDEBUG 0
#endif
#define YYMAXTOKEN 263
#if YYDEBUG
static YYCONST char *YYCONST yyname[] = {
"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,"'('","')'",0,0,"','",0,0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0,
"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
"TERMINAL","START","PPERCENT","ID","TEMPLATE","CODE","INT",
};
static YYCONST char *YYCONST yyrule[] = {
"$accept : spec",
"spec : decls PPERCENT rules",
"spec : decls",
"decls :",
"decls : decls decl",
"decl : TERMINAL blist '\\n'",
"decl : START nonterm '\\n'",
"decl : '\\n'",
"decl : error '\\n'",
"blist :",
"blist : blist ID '=' INT",
"rules :",
"rules : rules nonterm ':' tree TEMPLATE cost '\\n'",
"rules : rules '\\n'",
"rules : rules error '\\n'",
"nonterm : ID",
"tree : ID",
"tree : ID '(' tree ')'",
"tree : ID '(' tree ',' tree ')'",
"cost : CODE",
};
#endif
#define YYLEX yylex()
#define YYEMPTY -1
#define yyclearin (yychar=(YYEMPTY))
#define yyerrok (yyerrflag=0)
#ifndef YYINITDEPTH
#define YYINITDEPTH 200
#endif
#ifdef YYSTACKSIZE
#ifndef YYMAXDEPTH
#define YYMAXDEPTH YYSTACKSIZE
#endif
#else
#ifdef YYMAXDEPTH
#define YYSTACKSIZE YYMAXDEPTH
#else
#define YYSTACKSIZE 500
#define YYMAXDEPTH 500
#endif
#endif
#ifndef YYMAXSTACKSIZE
#define YYMAXSTACKSIZE 10000
#endif
int yydebug;
int yynerrs;
int yyerrflag;
int yychar;
YYSTYPE yyval;
YYSTYPE yylval;
static short *yyss;
static YYSTYPE *yyvs;
static int yystacksize;
#define yyfree(x) free(x)
extern int yylex();
static YYPTR
YYDEFUN (yymalloc, (bytes), unsigned bytes)
{
YYPTR ptr = (YYPTR) malloc (bytes);
if (ptr != 0) return (ptr);
yyerror ("yyparse: memory exhausted");
return (0);
}
static YYPTR
YYDEFUN (yyrealloc, (old, bytes), YYPTR old YYAND unsigned bytes)
{
YYPTR ptr = (YYPTR) realloc (old, bytes);
if (ptr != 0) return (ptr);
yyerror ("yyparse: memory exhausted");
return (0);
}
static int
#ifdef __GNUC__
inline
#endif
yygrow ()
{
#if YYDEBUG
int old_stacksize = yystacksize;
#endif
short *new_yyss;
YYSTYPE *new_yyvs;
if (yystacksize == YYMAXSTACKSIZE)
return (1);
yystacksize += (yystacksize + 1 ) / 2;
if (yystacksize > YYMAXSTACKSIZE)
yystacksize = YYMAXSTACKSIZE;
#if YYDEBUG
if (yydebug)
printf("yydebug: growing stack size from %d to %d\n",
old_stacksize, yystacksize);
#endif
new_yyss = (short *) yyrealloc ((char *)yyss, yystacksize * sizeof (short));
if (new_yyss == 0)
return (1);
new_yyvs = (YYSTYPE *) yyrealloc ((char *)yyvs, yystacksize * sizeof (YYSTYPE));
if (new_yyvs == 0)
{
yyfree (new_yyss);
return (1);
}
yyss = new_yyss;
yyvs = new_yyvs;
return (0);
}
#line 60 "lburg/gram.y"
#include <assert.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
int errcnt = 0;
FILE *infp = NULL;
FILE *outfp = NULL;
static char buf[BUFSIZ], *bp = buf;
static int ppercent = 0;
static int code = 0;
static int get(void) {
if (*bp == 0) {
bp = buf;
*bp = 0;
if (fgets(buf, sizeof buf, infp) == NULL)
return EOF;
yylineno++;
while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') {
for (;;) {
if (fgets(buf, sizeof buf, infp) == NULL) {
yywarn("unterminated %{...%}\n");
return EOF;
}
yylineno++;
if (strcmp(buf, "%}\n") == 0)
break;
fputs(buf, outfp);
}
if (fgets(buf, sizeof buf, infp) == NULL)
return EOF;
yylineno++;
}
}
return *bp++;
}
void yyerror(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
if (yylineno > 0)
fprintf(stderr, "line %d: ", yylineno);
vfprintf(stderr, fmt, ap);
if (fmt[strlen(fmt)-1] != '\n')
fprintf(stderr, "\n");
errcnt++;
va_end(ap);
}
int yylex(void) {
int c;
if (code) {
char *p;
bp += strspn(bp, " \t\f");
p = strchr(bp, '\n');
if (p == NULL)
p = strchr(bp, '\n');
while (p > bp && isspace(p[-1]))
p--;
yylval.string = alloc(p - bp + 1);
strncpy(yylval.string, bp, p - bp);
yylval.string[p - bp] = 0;
bp = p;
code--;
return CODE;
}
while ((c = get()) != EOF) {
switch (c) {
case ' ': case '\f': case '\t':
continue;
case '\n':
case '(': case ')': case ',':
case ':': case '=':
return c;
}
if (c == '%' && *bp == '%') {
bp++;
return ppercent++ ? 0 : PPERCENT;
} else if (c == '%' && strncmp(bp, "term", 4) == 0
&& isspace(bp[4])) {
bp += 4;
return TERMINAL;
} else if (c == '%' && strncmp(bp, "start", 5) == 0
&& isspace(bp[5])) {
bp += 5;
return START;
} else if (c == '"') {
char *p = strchr(bp, '"');
if (p == NULL) {
yyerror("missing \" in assembler template\n");
p = strchr(bp, '\n');
if (p == NULL)
p = strchr(bp, '\0');
}
assert(p);
yylval.string = alloc(p - bp + 1);
strncpy(yylval.string, bp, p - bp);
yylval.string[p - bp] = 0;
bp = *p == '"' ? p + 1 : p;
code++;
return TEMPLATE;
} else if (isdigit(c)) {
int n = 0;
do {
int d = c - '0';
if (n > (INT_MAX - d)/10)
yyerror("integer greater than %d\n", INT_MAX);
else
n = 10*n + d;
c = get();
} while (c != EOF && isdigit(c));
bp--;
yylval.n = n;
return INT;
} else if (isalpha(c)) {
char *p = bp - 1;
while (isalpha(*bp) || isdigit(*bp) || *bp == '_')
bp++;
yylval.string = alloc(bp - p + 1);
strncpy(yylval.string, p, bp - p);
yylval.string[bp - p] = 0;
return ID;
} else if (isprint(c))
yyerror("invalid character `%c'\n", c);
else
yyerror("invalid character `\\%03o'\n", (unsigned char)c);
}
return 0;
}
void yywarn(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
if (yylineno > 0)
fprintf(stderr, "line %d: ", yylineno);
fprintf(stderr, "warning: ");
vfprintf(stderr, fmt, ap);
}
#line 403 "y.tab.c"
#define YYABORT goto yyabort
#define YYACCEPT goto yyaccept
#define YYERROR goto yyerrlab
#if YYDEBUG
#ifdef __cplusplus
extern "C" char *getenv();
#else
extern char *getenv();
#endif
#endif
int
yyparse()
{
register int yym, yyn, yystate;
register YYSTYPE *yyvsp;
register short *yyssp;
short *yysse;
#if YYDEBUG
register YYCONST char *yys;
if (yys = getenv("YYDEBUG"))
{
yyn = *yys;
if (yyn >= '0' && yyn <= '9')
yydebug = yyn - '0';
}
#endif
yynerrs = 0;
yyerrflag = 0;
yychar = (-1);
if (yyss == 0)
{
yyss = (short *) yymalloc (YYSTACKSIZE * sizeof (short));
if (yyss == 0)
goto yyabort;
yyvs = (YYSTYPE *) yymalloc (YYSTACKSIZE * sizeof (YYSTYPE));
if (yyvs == 0)
{
yyfree (yyss);
goto yyabort;
}
yystacksize = YYSTACKSIZE;
}
yysse = yyss + yystacksize - 1;
yyssp = yyss;
yyvsp = yyvs;
*yyssp = yystate = 0;
goto yyloop;
yypush_lex:
yyval = yylval;
yystate = yytable[yyn];
yypush:
if (yyssp >= yysse)
{
int depth = yyssp - yyss;
if (yygrow() != 0)
goto yyoverflow;
yysse = yyss + yystacksize -1;
yyssp = depth + yyss;
yyvsp = depth + yyvs;
}
*++yyssp = yystate;
*++yyvsp = yyval;
yyloop:
if ((yyn = yydefred[yystate])) goto yyreduce;
yyn = yysindex[yystate];
if (yychar < 0)
{
if ((yychar = yylex()) < 0) yychar = 0;
#if YYDEBUG
if (yydebug)
{
yys = 0;
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
if (!yys) yys = "illegal-symbol";
printf("yydebug: state %d, reading %d (%s)\n", yystate,
yychar, yys);
}
#endif
}
if (yyn != 0
&& ((yyn += yychar), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
&& yycheck[yyn] == yychar)
{
#if YYDEBUG
if (yydebug)
printf("yydebug: state %d, shifting to state %d\n",
yystate, yytable[yyn]);
#endif
if (yyerrflag > 0) --yyerrflag;
yychar = (-1);
goto yypush_lex;
}
yyn = yyrindex[yystate];
if (yyn != 0
&& ((yyn += yychar), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
&& yycheck[yyn] == yychar)
{
yyn = yytable[yyn];
goto yyreduce;
}
if (yyerrflag) goto yyinrecovery;
#ifdef lint
goto yynewerror;
yynewerror:
#endif
yyerror("syntax error");
#ifdef lint
goto yyerrlab;
yyerrlab:
#endif
++yynerrs;
yyinrecovery:
if (yyerrflag < 3)
{
yyerrflag = 3;
for (;;)
{
yyn = yysindex[*yyssp];
if (yyn != 0
&& ((yyn += YYERRCODE), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
&& yycheck[yyn] == YYERRCODE)
{
#if YYDEBUG
if (yydebug)
printf("yydebug: state %d, error recovery shifting\
to state %d\n", *yyssp, yytable[yyn]);
#endif
goto yypush_lex;
}
else
{
#if YYDEBUG
if (yydebug)
printf("yydebug: error recovery discarding state %d\n",
*yyssp);
#endif
if (yyssp <= yyss) goto yyabort;
--yyssp;
--yyvsp;
}
}
}
else
{
if (yychar == 0) goto yyabort;
#if YYDEBUG
if (yydebug)
{
yys = 0;
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
if (!yys) yys = "illegal-symbol";
printf("yydebug: state %d, error recovery discards token %d (%s)\n",
yystate, yychar, yys);
}
#endif
yychar = (-1);
goto yyloop;
}
yyreduce:
#if YYDEBUG
if (yydebug)
printf("yydebug: state %d, reducing by rule %d (%s)\n",
yystate, yyn, yyrule[yyn]);
#endif
yym = yylen[yyn];
yyval = yyvsp[1-yym];
switch (yyn)
{
case 1:
#line 22 "lburg/gram.y"
{ yylineno = 0; }
break;
case 2:
#line 23 "lburg/gram.y"
{ yylineno = 0; }
break;
case 6:
#line 31 "lburg/gram.y"
{
if (nonterm(yyvsp[-1].string)->number != 1)
yyerror("redeclaration of the start symbol\n");
}
break;
case 8:
#line 36 "lburg/gram.y"
{ yyerrok; }
break;
case 10:
#line 40 "lburg/gram.y"
{ term(yyvsp[-2].string, yyvsp[0].n); }
break;
case 12:
#line 44 "lburg/gram.y"
{ rule(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-2].string, yyvsp[-1].string); }
break;
case 14:
#line 46 "lburg/gram.y"
{ yyerrok; }
break;
case 15:
#line 49 "lburg/gram.y"
{ nonterm(yyval.string = yyvsp[0].string); }
break;
case 16:
#line 52 "lburg/gram.y"
{ yyval.tree = tree(yyvsp[0].string, 0, 0); }
break;
case 17:
#line 53 "lburg/gram.y"
{ yyval.tree = tree(yyvsp[-3].string, yyvsp[-1].tree, 0); }
break;
case 18:
#line 54 "lburg/gram.y"
{ yyval.tree = tree(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-1].tree); }
break;
case 19:
#line 57 "lburg/gram.y"
{ if (*yyvsp[0].string == 0) yyval.string = "0"; }
break;
#line 630 "y.tab.c"
}
yyssp -= yym;
yyvsp -= yym;
yym = yylhs[yyn];
yystate = *yyssp;
if (yystate == 0 && yym == 0)
{
#if YYDEBUG
if (yydebug)
printf("yydebug: after reduction, shifting from state 0 to\
state %d\n", YYFINAL);
#endif
yystate = YYFINAL;
*++yyssp = YYFINAL;
*++yyvsp = yyval;
if (yychar < 0)
{
if ((yychar = yylex()) < 0) yychar = 0;
#if YYDEBUG
if (yydebug)
{
yys = 0;
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
if (!yys) yys = "illegal-symbol";
printf("yydebug: state %d, reading %d (%s)\n",
YYFINAL, yychar, yys);
}
#endif
}
if (yychar == 0) goto yyaccept;
goto yyloop;
}
yyn = yygindex[yym];
if (yyn != 0
&& ((yyn += yystate), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
&& yycheck[yyn] == yystate)
yystate = yytable[yyn];
else
yystate = yydgoto[yym];
#if YYDEBUG
if (yydebug)
printf("yydebug: after reduction, shifting from state %d \
to state %d\n", *yyssp, yystate);
#endif
goto yypush;
yyoverflow:
yyerror("yacc stack overflow");
yyabort:
return (1);
yyaccept:
return (0);
}

View File

@@ -1,202 +0,0 @@
%{
#include <stdio.h>
#include "lburg.h"
static char rcsid[] = "$Id: gram.y 145 2001-10-17 21:53:10Z timo $";
/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */
static int yylineno = 0;
%}
%union {
int n;
char *string;
Tree tree;
}
%term TERMINAL
%term START
%term PPERCENT
%token <string> ID TEMPLATE CODE
%token <n> INT
%type <string> nonterm cost
%type <tree> tree
%%
spec : decls PPERCENT rules { yylineno = 0; }
| decls { yylineno = 0; }
;
decls : /* lambda */
| decls decl
;
decl : TERMINAL blist '\n'
| START nonterm '\n' {
if (nonterm($2)->number != 1)
yyerror("redeclaration of the start symbol\n");
}
| '\n'
| error '\n' { yyerrok; }
;
blist : /* lambda */
| blist ID '=' INT { term($2, $4); }
;
rules : /* lambda */
| rules nonterm ':' tree TEMPLATE cost '\n' { rule($2, $4, $5, $6); }
| rules '\n'
| rules error '\n' { yyerrok; }
;
nonterm : ID { nonterm($$ = $1); }
;
tree : ID { $$ = tree($1, 0, 0); }
| ID '(' tree ')' { $$ = tree($1, $3, 0); }
| ID '(' tree ',' tree ')' { $$ = tree($1, $3, $5); }
;
cost : CODE { if (*$1 == 0) $$ = "0"; }
;
%%
#include <assert.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
int errcnt = 0;
FILE *infp = NULL;
FILE *outfp = NULL;
static char buf[BUFSIZ], *bp = buf;
static int ppercent = 0;
static int code = 0;
static int get(void) {
if (*bp == 0) {
bp = buf;
*bp = 0;
if (fgets(buf, sizeof buf, infp) == NULL)
return EOF;
yylineno++;
while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') {
for (;;) {
if (fgets(buf, sizeof buf, infp) == NULL) {
yywarn("unterminated %{...%}\n");
return EOF;
}
yylineno++;
if (strcmp(buf, "%}\n") == 0)
break;
fputs(buf, outfp);
}
if (fgets(buf, sizeof buf, infp) == NULL)
return EOF;
yylineno++;
}
}
return *bp++;
}
void yyerror(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
if (yylineno > 0)
fprintf(stderr, "line %d: ", yylineno);
vfprintf(stderr, fmt, ap);
if (fmt[strlen(fmt)-1] != '\n')
fprintf(stderr, "\n");
errcnt++;
va_end(ap);
}
int yylex(void) {
int c;
if (code) {
char *p;
bp += strspn(bp, " \t\f");
p = strchr(bp, '\n');
if (p == NULL)
p = strchr(bp, '\n');
while (p > bp && isspace(p[-1]))
p--;
yylval.string = alloc(p - bp + 1);
strncpy(yylval.string, bp, p - bp);
yylval.string[p - bp] = 0;
bp = p;
code--;
return CODE;
}
while ((c = get()) != EOF) {
switch (c) {
case ' ': case '\f': case '\t':
continue;
case '\n':
case '(': case ')': case ',':
case ':': case '=':
return c;
}
if (c == '%' && *bp == '%') {
bp++;
return ppercent++ ? 0 : PPERCENT;
} else if (c == '%' && strncmp(bp, "term", 4) == 0
&& isspace(bp[4])) {
bp += 4;
return TERMINAL;
} else if (c == '%' && strncmp(bp, "start", 5) == 0
&& isspace(bp[5])) {
bp += 5;
return START;
} else if (c == '"') {
char *p = strchr(bp, '"');
if (p == NULL) {
yyerror("missing \" in assembler template\n");
p = strchr(bp, '\n');
if (p == NULL)
p = strchr(bp, '\0');
}
assert(p);
yylval.string = alloc(p - bp + 1);
strncpy(yylval.string, bp, p - bp);
yylval.string[p - bp] = 0;
bp = *p == '"' ? p + 1 : p;
code++;
return TEMPLATE;
} else if (isdigit(c)) {
int n = 0;
do {
int d = c - '0';
if (n > (INT_MAX - d)/10)
yyerror("integer greater than %d\n", INT_MAX);
else
n = 10*n + d;
c = get();
} while (c != EOF && isdigit(c));
bp--;
yylval.n = n;
return INT;
} else if (isalpha(c)) {
char *p = bp - 1;
while (isalpha(*bp) || isdigit(*bp) || *bp == '_')
bp++;
yylval.string = alloc(bp - p + 1);
strncpy(yylval.string, p, bp - p);
yylval.string[bp - p] = 0;
return ID;
} else if (isprint(c))
yyerror("invalid character `%c'\n", c);
else
yyerror("invalid character `\\%03o'\n", (unsigned char)c);
}
return 0;
}
void yywarn(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
if (yylineno > 0)
fprintf(stderr, "line %d: ", yylineno);
fprintf(stderr, "warning: ");
vfprintf(stderr, fmt, ap);
}

View File

@@ -1,179 +0,0 @@
.TH LBURG 1 "local \- 11/30/94"
.\" $Id: lburg.1 145 2001-10-17 21:53:10Z timo $
.SH NAME
lburg \- lcc's code-generator generator
.SH SYNOPSIS
.B lburg
[
.I option
]...
[ [
.I input
]
.I output
]
.br
.SH DESCRIPTION
.PP
.I lburg
reads an lcc-style BURG specification from
.I input
and writes a pattern-matching code generator to
.IR output .
If
.I input
is `\-' or is omitted,
.I lburg
reads the standard input;
If
.I output
is `\-' or is omitted,
.I lburg
writes to the standard output.
.PP
.I lburg
accepts specifications that conform to the following EBNF grammar.
Terminals are enclosed in single quotes or are
given in uppercase, all other symbols are nonterminals or English phrases,
{X} denotes zero or more instances of X, and [X] denotes an optional X.
.PP
.nf
.RS
.ft CW
spec: `%{' configuration `%}' { dcl } `%%' { rule }
[ `%%' C code ]
dcl: `%start' nonterm
`%term' { ID `=' INT }
rule: nonterm `:' tree template [ C expression ]
tree: term `(' tree `,' tree `)'
term `(' tree `)'
term
nonterm
nonterm: ID
template: `"' { any character except double quote } `"'
.RE
.fi
.PP
Specifications are structurally similar to
.IR yacc 's.
Text between
`\f(CW%{\fP'
and
`\f(CW%}\fP'
is called the configuration section; there may be several such segments.
All are concatenated and copied verbatim into the head of the output.
Text after the second
`\f(CW%%\fP',
if any, is also copied verbatim into the output, at the end.
.PP
Specifications consist of declarations, a
`\f(CW%%\fP'
separator, and rules.
Input is line-oriented; each declaration and rule must appear on a separate line,
and declarations must begin in column 1.
Declarations declare terminals \(em the operators in subject
trees \(em and associate a unique, positive external symbol
number with each one.
Nonterminals are declared by their presence
on the left side of rules. The
\f(CW%start\fP
declaration optionally declares a nonterminal as the start symbol.
In the grammar above,
\f(CWterm\fP
and
\f(CWnonterm\fP
denote identifiers that are terminals and nonterminals.
.PP
Rules define tree patterns in a fully parenthesized prefix
form. Every nonterminal denotes a tree.
Each operator has a fixed
arity, which is inferred from the rules in which it is used.
A chain rule is a rule whose pattern is another nonterminal.
If no start symbol is declared, the nonterminal defined by the first rule is used.
.PP
Each rule ends with an expression that computes the cost of matching
that rule; omitted costs
default to zero. Costs of chain rules must be constants.
.PP
The configuration section configures the output
for the trees being parsed and the client's environment.
As shown, this section must define
\f(CWNODEPTR_TYPE\fP
to be a visible typedef symbol for a pointer to a
node in the subject tree.
The labeller invokes
\f(CWOP_LABEL(p)\fP,
\f(CWLEFT\_CHILD(p)\fP, and
\f(CWRIGHT\_CHILD(p)\fP
to read the operator and children from the node pointed to by \f(CWp\fP.
If the configuration section defines these operations as macros, they are implemented in-line;
otherwise, they must be implemented as functions.
.PP
The matcher
computes and stores a single integral state in each node of the subject tree.
The configuration section must define a macro
\f(CWSTATE_LABEL(p)\fP
to access the state field of the node pointed to
by \f(CWp\fP. It must be large enough to hold a pointer, and
a macro is required because it is used as an lvalue.
.PP
.SH OPTIONS
.TP
.BI \-p \ prefix
.br
.ns
.TP
.BI \-p prefix
Use
.I prefix
as the disambiquating prefix for visible names and fields.
The default is `\f(CW_\fP'.
.TP
.B \-T
Arrange for
.sp
.nf
.ft CW
void _trace(NODEPTR_TYPE p, int eruleno,
int cost, int bestcost);
.sp
.fi
.ft R
to be called at each successful match.
\f(CWp\fP
identifies the node and
\f(CWeruleno\fP
identifies the matching rule; the rules are numbered
beginning at 1 in the order they appear in the input.
\f(CWcost\fP
is the cost of the match and
\f(CWbestcost\fP
is the cost of the best previous match. The current match
wins only if
\f(CWcost\fP
is less than \f(CWbestcost\fP.
32767 represents the infinite cost of no previous match.
\f(CW_trace\fP must be declared in the configuration section.
.SH "SEE ALSO"
.IR lcc (1)
.PP
C. W. Fraser and D. R. Hanson,
.IR A Retargetable C Compiler: Design and Implementation ,
Benjamin/Cummings, Redwood City, CA, 1995,
ISBN 0-8053-1670-1. Chapter 14.
.PP
C. W. Fraser, D. R. Hanson and T. A. Proebsting,
`Engineering a simple, efficient code generator generator,'
.I
ACM Letters on Programming Languages and Systems
.BR 1 ,
3 (Sep. 1992), 213-226.
.br
.SH BUGS
Mail bug reports along with the shortest input
that exposes them to drh@cs.princeton.edu.

View File

@@ -1,671 +0,0 @@
#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "lburg.h"
static char rcsid[] = "lburg.c - faked rcsid";
static char *prefix = "";
static int Tflag = 0;
static int ntnumber = 0;
static Nonterm start = 0;
static Term terms;
static Nonterm nts;
static Rule rules;
static int nrules;
static struct block {
struct block *link;
} *memlist; /* list of allocated blocks */
static char *stringf(char *fmt, ...);
static void print(char *fmt, ...);
static void ckreach(Nonterm p);
static void emitclosure(Nonterm nts);
static void emitcost(Tree t, char *v);
static void emitdefs(Nonterm nts, int ntnumber);
static void emitheader(void);
static void emitkids(Rule rules, int nrules);
static void emitnts(Rule rules, int nrules);
static void emitrecalc(char *pre, Term root, Term kid);
static void emitrecord(char *pre, Rule r, char *c, int cost);
static void emitrule(Nonterm nts);
static void emitlabel(Term terms, Nonterm start, int ntnumber);
static void emitstring(Rule rules);
static void emitstruct(Nonterm nts, int ntnumber);
static void emittest(Tree t, char *v, char *suffix);
int main(int argc, char *argv[]) {
int c, i;
Nonterm p;
for (i = 1; i < argc; i++)
if (strcmp(argv[i], "-T") == 0)
Tflag = 1;
else if (strncmp(argv[i], "-p", 2) == 0 && argv[i][2])
prefix = &argv[i][2];
else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc)
prefix = argv[++i];
else if (*argv[i] == '-' && argv[i][1]) {
yyerror("usage: %s [-T | -p prefix]... [ [ input ] output ] \n",
argv[0]);
exit(1);
} else if (infp == NULL) {
if (strcmp(argv[i], "-") == 0)
infp = stdin;
else if ((infp = fopen(argv[i], "r")) == NULL) {
yyerror("%s: can't read `%s'\n", argv[0], argv[i]);
exit(1);
}
} else if (outfp == NULL) {
if (strcmp(argv[i], "-") == 0)
outfp = stdout;
if ((outfp = fopen(argv[i], "w")) == NULL) {
yyerror("%s: can't write `%s'\n", argv[0], argv[i]);
exit(1);
}
}
if (infp == NULL)
infp = stdin;
if (outfp == NULL)
outfp = stdout;
yyparse();
if (start)
ckreach(start);
for (p = nts; p; p = p->link) {
if (p->rules == NULL)
yyerror("undefined nonterminal `%s'\n", p->name);
if (!p->reached)
yyerror("can't reach nonterminal `%s'\n", p->name);
}
emitheader();
emitdefs(nts, ntnumber);
emitstruct(nts, ntnumber);
emitnts(rules, nrules);
emitstring(rules);
emitrule(nts);
emitclosure(nts);
if (start)
emitlabel(terms, start, ntnumber);
emitkids(rules, nrules);
if (!feof(infp))
while ((c = getc(infp)) != EOF)
putc(c, outfp);
while (memlist) { /* for purify */
struct block *q = memlist->link;
free(memlist);
memlist = q;
}
return errcnt > 0;
}
/* alloc - allocate nbytes or issue fatal error */
void *alloc(int nbytes) {
struct block *p = calloc(1, sizeof *p + nbytes);
if (p == NULL) {
yyerror("out of memory\n");
exit(1);
}
p->link = memlist;
memlist = p;
return p + 1;
}
/* stringf - format and save a string */
static char *stringf(char *fmt, ...) {
va_list ap;
char buf[512];
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
return strcpy(alloc(strlen(buf) + 1), buf);
}
struct entry {
union {
char *name;
struct term t;
struct nonterm nt;
} sym;
struct entry *link;
} *table[211];
#define HASHSIZE (sizeof table/sizeof table[0])
/* hash - return hash number for str */
static unsigned hash(char *str) {
unsigned h = 0;
while (*str)
h = (h<<1) + *str++;
return h;
}
/* lookup - lookup symbol name */
static void *lookup(char *name) {
struct entry *p = table[hash(name)%HASHSIZE];
for ( ; p; p = p->link)
if (strcmp(name, p->sym.name) == 0)
return &p->sym;
return 0;
}
/* install - install symbol name */
static void *install(char *name) {
struct entry *p = alloc(sizeof *p);
int i = hash(name)%HASHSIZE;
p->sym.name = name;
p->link = table[i];
table[i] = p;
return &p->sym;
}
/* nonterm - create a new terminal id, if necessary */
Nonterm nonterm(char *id) {
Nonterm p = lookup(id), *q = &nts;
if (p && p->kind == NONTERM)
return p;
if (p && p->kind == TERM)
yyerror("`%s' is a terminal\n", id);
p = install(id);
p->kind = NONTERM;
p->number = ++ntnumber;
if (p->number == 1)
start = p;
while (*q && (*q)->number < p->number)
q = &(*q)->link;
assert(*q == 0 || (*q)->number != p->number);
p->link = *q;
*q = p;
return p;
}
/* term - create a new terminal id with external symbol number esn */
Term term(char *id, int esn) {
Term p = lookup(id), *q = &terms;
if (p)
yyerror("redefinition of terminal `%s'\n", id);
else
p = install(id);
p->kind = TERM;
p->esn = esn;
p->arity = -1;
while (*q && (*q)->esn < p->esn)
q = &(*q)->link;
if (*q && (*q)->esn == p->esn)
yyerror("duplicate external symbol number `%s=%d'\n",
p->name, p->esn);
p->link = *q;
*q = p;
return p;
}
/* tree - create & initialize a tree node with the given fields */
Tree tree(char *id, Tree left, Tree right) {
Tree t = alloc(sizeof *t);
Term p = lookup(id);
int arity = 0;
if (left && right)
arity = 2;
else if (left)
arity = 1;
if (p == NULL && arity > 0) {
yyerror("undefined terminal `%s'\n", id);
p = term(id, -1);
} else if (p == NULL && arity == 0)
p = (Term)nonterm(id);
else if (p && p->kind == NONTERM && arity > 0) {
yyerror("`%s' is a nonterminal\n", id);
p = term(id, -1);
}
if (p->kind == TERM && p->arity == -1)
p->arity = arity;
if (p->kind == TERM && arity != p->arity)
yyerror("inconsistent arity for terminal `%s'\n", id);
t->op = p;
t->nterms = p->kind == TERM;
if ((t->left = left) != NULL)
t->nterms += left->nterms;
if ((t->right = right) != NULL)
t->nterms += right->nterms;
return t;
}
/* rule - create & initialize a rule with the given fields */
Rule rule(char *id, Tree pattern, char *template, char *code) {
Rule r = alloc(sizeof *r), *q;
Term p = pattern->op;
char *end;
r->lhs = nonterm(id);
r->packed = ++r->lhs->lhscount;
for (q = &r->lhs->rules; *q; q = &(*q)->decode)
;
*q = r;
r->pattern = pattern;
r->ern = ++nrules;
r->template = template;
r->code = code;
r->cost = strtol(code, &end, 10);
if (*end) {
r->cost = -1;
r->code = stringf("(%s)", code);
}
if (p->kind == TERM) {
for (q = &p->rules; *q; q = &(*q)->next)
;
*q = r;
} else if (pattern->left == NULL && pattern->right == NULL) {
Nonterm p = pattern->op;
r->chain = p->chain;
p->chain = r;
if (r->cost == -1)
yyerror("illegal nonconstant cost `%s'\n", code);
}
for (q = &rules; *q; q = &(*q)->link)
;
r->link = *q;
*q = r;
return r;
}
/* print - formatted output */
static void print(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
for ( ; *fmt; fmt++)
if (*fmt == '%')
switch (*++fmt) {
case 'd': fprintf(outfp, "%d", va_arg(ap, int)); break;
case 's': fputs(va_arg(ap, char *), outfp); break;
case 'P': fprintf(outfp, "%s_", prefix); break;
case 'T': {
Tree t = va_arg(ap, Tree);
print("%S", t->op);
if (t->left && t->right)
print("(%T,%T)", t->left, t->right);
else if (t->left)
print("(%T)", t->left);
break;
}
case 'R': {
Rule r = va_arg(ap, Rule);
print("%S: %T", r->lhs, r->pattern);
break;
}
case 'S': fputs(va_arg(ap, Term)->name, outfp); break;
case '1': case '2': case '3': case '4': case '5': {
int n = *fmt - '0';
while (n-- > 0)
putc('\t', outfp);
break;
}
default: putc(*fmt, outfp); break;
}
else
putc(*fmt, outfp);
va_end(ap);
}
/* reach - mark all nonterminals in tree t as reachable */
static void reach(Tree t) {
Nonterm p = t->op;
if (p->kind == NONTERM)
if (!p->reached)
ckreach(p);
if (t->left)
reach(t->left);
if (t->right)
reach(t->right);
}
/* ckreach - mark all nonterminals reachable from p */
static void ckreach(Nonterm p) {
Rule r;
p->reached = 1;
for (r = p->rules; r; r = r->decode)
reach(r->pattern);
}
/* emitcase - emit one case in function state */
static void emitcase(Term p, int ntnumber) {
Rule r;
print("%1case %d: /* %S */\n", p->esn, p);
switch (p->arity) {
case 0: case -1:
break;
case 1:
print("%2%Plabel(LEFT_CHILD(a));\n");
break;
case 2:
print("%2%Plabel(LEFT_CHILD(a));\n");
print("%2%Plabel(RIGHT_CHILD(a));\n");
break;
default: assert(0);
}
for (r = p->rules; r; r = r->next) {
char *indent = "\t\t\0";
switch (p->arity) {
case 0: case -1:
print("%2/* %R */\n", r);
if (r->cost == -1) {
print("%2c = %s;\n", r->code);
emitrecord("\t\t", r, "c", 0);
} else
emitrecord("\t\t", r, r->code, 0);
break;
case 1:
if (r->pattern->nterms > 1) {
print("%2if (%1/* %R */\n", r);
emittest(r->pattern->left, "LEFT_CHILD(a)", " ");
print("%2) {\n");
indent = "\t\t\t";
} else
print("%2/* %R */\n", r);
if (r->pattern->nterms == 2 && r->pattern->left
&& r->pattern->right == NULL)
emitrecalc(indent, r->pattern->op, r->pattern->left->op);
print("%sc = ", indent);
emitcost(r->pattern->left, "LEFT_CHILD(a)");
print("%s;\n", r->code);
emitrecord(indent, r, "c", 0);
if (indent[2])
print("%2}\n");
break;
case 2:
if (r->pattern->nterms > 1) {
print("%2if (%1/* %R */\n", r);
emittest(r->pattern->left, "LEFT_CHILD(a)",
r->pattern->right->nterms ? " && " : " ");
emittest(r->pattern->right, "RIGHT_CHILD(a)", " ");
print("%2) {\n");
indent = "\t\t\t";
} else
print("%2/* %R */\n", r);
print("%sc = ", indent);
emitcost(r->pattern->left, "LEFT_CHILD(a)");
emitcost(r->pattern->right, "RIGHT_CHILD(a)");
print("%s;\n", r->code);
emitrecord(indent, r, "c", 0);
if (indent[2])
print("%2}\n");
break;
default: assert(0);
}
}
print("%2break;\n");
}
/* emitclosure - emit the closure functions */
static void emitclosure(Nonterm nts) {
Nonterm p;
for (p = nts; p; p = p->link)
if (p->chain)
print("static void %Pclosure_%S(NODEPTR_TYPE, int);\n", p);
print("\n");
for (p = nts; p; p = p->link)
if (p->chain) {
Rule r;
print("static void %Pclosure_%S(NODEPTR_TYPE a, int c) {\n"
"%1struct %Pstate *p = STATE_LABEL(a);\n", p);
for (r = p->chain; r; r = r->chain)
emitrecord("\t", r, "c", r->cost);
print("}\n\n");
}
}
/* emitcost - emit cost computation for tree t */
static void emitcost(Tree t, char *v) {
Nonterm p = t->op;
if (p->kind == TERM) {
if (t->left)
emitcost(t->left, stringf("LEFT_CHILD(%s)", v));
if (t->right)
emitcost(t->right, stringf("RIGHT_CHILD(%s)", v));
} else
print("((struct %Pstate *)(%s->x.state))->cost[%P%S_NT] + ", v, p);
}
/* emitdefs - emit nonterminal defines and data structures */
static void emitdefs(Nonterm nts, int ntnumber) {
Nonterm p;
for (p = nts; p; p = p->link)
print("#define %P%S_NT %d\n", p, p->number);
print("\n");
print("static char *%Pntname[] = {\n%10,\n");
for (p = nts; p; p = p->link)
print("%1\"%S\",\n", p);
print("%10\n};\n\n");
}
/* emitheader - emit initial definitions */
static void emitheader(void) {
time_t timer = time(NULL);
print("/*\ngenerated at %sby %s\n*/\n", ctime(&timer), rcsid);
print("static void %Pkids(NODEPTR_TYPE, int, NODEPTR_TYPE[]);\n");
print("static void %Plabel(NODEPTR_TYPE);\n");
print("static int %Prule(void*, int);\n\n");
}
/* computekids - compute paths to kids in tree t */
static char *computekids(Tree t, char *v, char *bp, int *ip) {
Term p = t->op;
if (p->kind == NONTERM) {
sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v);
bp += strlen(bp);
} else if (p->arity > 0) {
bp = computekids(t->left, stringf("LEFT_CHILD(%s)", v), bp, ip);
if (p->arity == 2)
bp = computekids(t->right, stringf("RIGHT_CHILD(%s)", v), bp, ip);
}
return bp;
}
/* emitkids - emit _kids */
static void emitkids(Rule rules, int nrules) {
int i;
Rule r, *rc = alloc((nrules + 1 + 1)*sizeof *rc);
char **str = alloc((nrules + 1 + 1)*sizeof *str);
for (i = 0, r = rules; r; r = r->link) {
int j = 0;
char buf[1024], *bp = buf;
*computekids(r->pattern, "p", bp, &j) = 0;
for (j = 0; str[j] && strcmp(str[j], buf); j++)
;
if (str[j] == NULL)
str[j] = strcpy(alloc(strlen(buf) + 1), buf);
r->kids = rc[j];
rc[j] = r;
}
print("static void %Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n"
"%1if (!p)\n%2fatal(\"%Pkids\", \"Null tree\\n\", 0);\n"
"%1if (!kids)\n%2fatal(\"%Pkids\", \"Null kids\\n\", 0);\n"
"%1switch (eruleno) {\n");
for (i = 0; (r = rc[i]) != NULL; i++) {
for ( ; r; r = r->kids)
print("%1case %d: /* %R */\n", r->ern, r);
print("%s%2break;\n", str[i]);
}
print("%1default:\n%2fatal(\"%Pkids\", \"Bad rule number %%d\\n\", eruleno);\n%1}\n}\n\n");
}
/* emitlabel - emit label function */
static void emitlabel(Term terms, Nonterm start, int ntnumber) {
int i;
Term p;
print("static void %Plabel(NODEPTR_TYPE a) {\n%1int c;\n"
"%1struct %Pstate *p;\n\n"
"%1if (!a)\n%2fatal(\"%Plabel\", \"Null tree\\n\", 0);\n");
print("%1STATE_LABEL(a) = p = allocate(sizeof *p, FUNC);\n"
"%1p->rule._stmt = 0;\n");
for (i = 1; i <= ntnumber; i++)
print("%1p->cost[%d] =\n", i);
print("%20x7fff;\n%1switch (OP_LABEL(a)) {\n");
for (p = terms; p; p = p->link)
emitcase(p, ntnumber);
print("%1default:\n"
"%2fatal(\"%Plabel\", \"Bad terminal %%d\\n\", OP_LABEL(a));\n%1}\n}\n\n");
}
/* computents - fill in bp with _nts vector for tree t */
static char *computents(Tree t, char *bp) {
if (t) {
Nonterm p = t->op;
if (p->kind == NONTERM) {
sprintf(bp, "%s_%s_NT, ", prefix, p->name);
bp += strlen(bp);
} else
bp = computents(t->right, computents(t->left, bp));
}
return bp;
}
/* emitnts - emit _nts ragged array */
static void emitnts(Rule rules, int nrules) {
Rule r;
int i, j, *nts = alloc((nrules + 1)*sizeof *nts);
char **str = alloc((nrules + 1)*sizeof *str);
for (i = 0, r = rules; r; r = r->link) {
char buf[1024];
*computents(r->pattern, buf) = 0;
for (j = 0; str[j] && strcmp(str[j], buf); j++)
;
if (str[j] == NULL) {
print("static short %Pnts_%d[] = { %s0 };\n", j, buf);
str[j] = strcpy(alloc(strlen(buf) + 1), buf);
}
nts[i++] = j;
}
print("\nstatic short *%Pnts[] = {\n");
for (i = j = 0, r = rules; r; r = r->link) {
for ( ; j < r->ern; j++)
print("%10,%1/* %d */\n", j);
print("%1%Pnts_%d,%1/* %d */\n", nts[i++], j++);
}
print("};\n\n");
}
/* emitrecalc - emit code that tests for recalculation of INDIR?(VREGP) */
static void emitrecalc(char *pre, Term root, Term kid) {
if (root->kind == TERM && strncmp(root->name, "INDIR", 5) == 0
&& kid->kind == TERM && strcmp(kid->name, "VREGP" ) == 0) {
Nonterm p;
print("%sif (mayrecalc(a)) {\n", pre);
print("%s%1struct %Pstate *q = a->syms[RX]->u.t.cse->x.state;\n", pre);
for (p = nts; p; p = p->link) {
print("%s%1if (q->cost[%P%S_NT] == 0) {\n", pre, p);
print("%s%2p->cost[%P%S_NT] = 0;\n", pre, p);
print("%s%2p->rule.%P%S = q->rule.%P%S;\n", pre, p, p);
print("%s%1}\n", pre);
}
print("%s}\n", pre);
}
}
/* emitrecord - emit code that tests for a winning match of rule r */
static void emitrecord(char *pre, Rule r, char *c, int cost) {
if (Tflag)
print("%s%Ptrace(a, %d, %s + %d, p->cost[%P%S_NT]);\n",
pre, r->ern, c, cost, r->lhs);
print("%sif (", pre);
print("%s + %d < p->cost[%P%S_NT]) {\n"
"%s%1p->cost[%P%S_NT] = %s + %d;\n%s%1p->rule.%P%S = %d;\n",
c, cost, r->lhs, pre, r->lhs, c, cost, pre, r->lhs,
r->packed);
if (r->lhs->chain)
print("%s%1%Pclosure_%S(a, %s + %d);\n", pre, r->lhs, c, cost);
print("%s}\n", pre);
}
/* emitrule - emit decoding vectors and _rule */
static void emitrule(Nonterm nts) {
Nonterm p;
for (p = nts; p; p = p->link) {
Rule r;
print("static short %Pdecode_%S[] = {\n%10,\n", p);
for (r = p->rules; r; r = r->decode)
print("%1%d,\n", r->ern);
print("};\n\n");
}
print("static int %Prule(void *state, int goalnt) {\n"
"%1if (goalnt < 1 || goalnt > %d)\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n"
"%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", ntnumber);
for (p = nts; p; p = p->link)
print("%1case %P%S_NT:"
"%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", p, p, p);
print("%1default:\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n%2return 0;\n%1}\n}\n\n");
}
/* emitstring - emit arrays of templates, instruction flags, and rules */
static void emitstring(Rule rules) {
Rule r;
print("static char *%Ptemplates[] = {\n");
print("/* 0 */%10,\n");
for (r = rules; r; r = r->link)
print("/* %d */%1\"%s\",%1/* %R */\n", r->ern, r->template, r);
print("};\n");
print("\nstatic char %Pisinstruction[] = {\n");
print("/* 0 */%10,\n");
for (r = rules; r; r = r->link) {
int len = strlen(r->template);
print("/* %d */%1%d,%1/* %s */\n", r->ern,
len >= 2 && r->template[len-2] == '\\' && r->template[len-1] == 'n',
r->template);
}
print("};\n");
print("\nstatic char *%Pstring[] = {\n");
print("/* 0 */%10,\n");
for (r = rules; r; r = r->link)
print("/* %d */%1\"%R\",\n", r->ern, r);
print("};\n\n");
}
/* emitstruct - emit the definition of the state structure */
static void emitstruct(Nonterm nts, int ntnumber) {
print("struct %Pstate {\n%1short cost[%d];\n%1struct {\n", ntnumber + 1);
for ( ; nts; nts = nts->link) {
int n = 1, m = nts->lhscount;
while ((m >>= 1) != 0)
n++;
print("%2unsigned int %P%S:%d;\n", nts, n);
}
print("%1} rule;\n};\n\n");
}
/* emittest - emit clause for testing a match */
static void emittest(Tree t, char *v, char *suffix) {
Term p = t->op;
if (p->kind == TERM) {
print("%3%s->op == %d%s/* %S */\n", v, p->esn,
t->nterms > 1 ? " && " : suffix, p);
if (t->left)
emittest(t->left, stringf("LEFT_CHILD(%s)", v),
t->right && t->right->nterms ? " && " : suffix);
if (t->right)
emittest(t->right, stringf("RIGHT_CHILD(%s)", v), suffix);
}
}

View File

@@ -1,65 +0,0 @@
#ifndef BURG_INCLUDED
#define BURG_INCLUDED
/* iburg.c: */
extern void *alloc(int nbytes);
typedef enum { TERM=1, NONTERM } Kind;
typedef struct rule *Rule;
typedef struct term *Term;
struct term { /* terminals: */
char *name; /* terminal name */
Kind kind; /* TERM */
int esn; /* external symbol number */
int arity; /* operator arity */
Term link; /* next terminal in esn order */
Rule rules; /* rules whose pattern starts with term */
};
typedef struct nonterm *Nonterm;
struct nonterm { /* nonterminals: */
char *name; /* nonterminal name */
Kind kind; /* NONTERM */
int number; /* identifying number */
int lhscount; /* # times nt appears in a rule lhs */
int reached; /* 1 iff reached from start nonterminal */
Rule rules; /* rules w/nonterminal on lhs */
Rule chain; /* chain rules w/nonterminal on rhs */
Nonterm link; /* next terminal in number order */
};
extern Nonterm nonterm(char *id);
extern Term term(char *id, int esn);
typedef struct tree *Tree;
struct tree { /* tree patterns: */
void *op; /* a terminal or nonterminal */
Tree left, right; /* operands */
int nterms; /* number of terminal nodes in this tree */
};
extern Tree tree(char *op, Tree left, Tree right);
struct rule { /* rules: */
Nonterm lhs; /* lefthand side nonterminal */
Tree pattern; /* rule pattern */
int ern; /* external rule number */
int packed; /* packed external rule number */
int cost; /* cost, if a constant */
char *code; /* cost, if an expression */
char *template; /* assembler template */
Rule link; /* next rule in ern order */
Rule next; /* next rule with same pattern root */
Rule chain; /* next chain rule with same rhs */
Rule decode; /* next rule with same lhs */
Rule kids; /* next rule with same _kids pattern */
};
extern Rule rule(char *id, Tree pattern, char *template, char *code);
/* gram.y: */
void yyerror(char *fmt, ...);
int yyparse(void);
void yywarn(char *fmt, ...);
extern int errcnt;
extern FILE *infp;
extern FILE *outfp;
#endif

View File

@@ -1,94 +0,0 @@
#include "c.h"
struct block {
struct block *next;
char *limit;
char *avail;
};
union align {
long l;
char *p;
double d;
int (*f)(void);
};
union header {
struct block b;
union align a;
};
#ifdef PURIFY
union header *arena[3];
void *allocate(unsigned long n, unsigned a) {
union header *new = malloc(sizeof *new + n);
assert(a < NELEMS(arena));
if (new == NULL) {
error("insufficient memory\n");
exit(1);
}
new->b.next = (void *)arena[a];
arena[a] = new;
return new + 1;
}
void deallocate(unsigned a) {
union header *p, *q;
assert(a < NELEMS(arena));
for (p = arena[a]; p; p = q) {
q = (void *)p->b.next;
free(p);
}
arena[a] = NULL;
}
void *newarray(unsigned long m, unsigned long n, unsigned a) {
return allocate(m*n, a);
}
#else
static struct block
first[] = { { NULL }, { NULL }, { NULL } },
*arena[] = { &first[0], &first[1], &first[2] };
static struct block *freeblocks;
void *allocate(unsigned long n, unsigned a) {
struct block *ap;
assert(a < NELEMS(arena));
assert(n > 0);
ap = arena[a];
n = roundup(n, sizeof (union align));
while (n > ap->limit - ap->avail) {
if ((ap->next = freeblocks) != NULL) {
freeblocks = freeblocks->next;
ap = ap->next;
} else
{
unsigned m = sizeof (union header) + n + roundup(10*1024, sizeof (union align));
ap->next = malloc(m);
ap = ap->next;
if (ap == NULL) {
error("insufficient memory\n");
exit(1);
}
ap->limit = (char *)ap + m;
}
ap->avail = (char *)((union header *)ap + 1);
ap->next = NULL;
arena[a] = ap;
}
ap->avail += n;
return ap->avail - n;
}
void *newarray(unsigned long m, unsigned long n, unsigned a) {
return allocate(m*n, a);
}
void deallocate(unsigned a) {
assert(a < NELEMS(arena));
arena[a]->next = freeblocks;
freeblocks = first[a].next;
first[a].next = NULL;
arena[a] = &first[a];
}
#endif

View File

@@ -1,8 +0,0 @@
#include "c.h"
extern Interface nullIR;
extern Interface bytecodeIR;
Binding bindings[] = {
{ "null", &nullIR },
{ "bytecode", &bytecodeIR },
{ NULL, NULL },
};

View File

@@ -1,366 +0,0 @@
#include "c.h"
#define I(f) b_##f
static void I(segment)(int n) {
static int cseg;
if (cseg != n)
switch (cseg = n) {
case CODE: print("code\n"); return;
case DATA: print("data\n"); return;
case BSS: print("bss\n"); return;
case LIT: print("lit\n"); return;
default: assert(0);
}
}
static void I(address)(Symbol q, Symbol p, long n) {
q->x.name = stringf("%s%s%D", p->x.name, n > 0 ? "+" : "", n);
}
static void I(defaddress)(Symbol p) {
print("address %s\n", p->x.name);
}
static void I(defconst)(int suffix, int size, Value v) {
switch (suffix) {
case I:
if (size > sizeof (int))
print("byte %d %D\n", size, v.i);
else
print("byte %d %d\n", size, v.i);
return;
case U:
if (size > sizeof (unsigned))
print("byte %d %U\n", size, v.u);
else
print("byte %d %u\n", size, v.u);
return;
case P: print("byte %d %U\n", size, (unsigned long)v.p); return;
case F:
if (size == 4) {
floatint_t fi;
fi.f = v.d;
print("byte 4 %u\n", fi.ui);
} else {
unsigned *p = (unsigned *)&v.d;
print("byte 4 %u\n", p[swap]);
print("byte 4 %u\n", p[1 - swap]);
}
return;
}
assert(0);
}
static void I(defstring)(int len, char *str) {
char *s;
for (s = str; s < str + len; s++)
print("byte 1 %d\n", (*s)&0377);
}
static void I(defsymbol)(Symbol p) {
if (p->scope == CONSTANTS)
switch (optype(ttob(p->type))) {
case I: p->x.name = stringf("%D", p->u.c.v.i); break;
case U: p->x.name = stringf("%U", p->u.c.v.u); break;
case P: p->x.name = stringf("%U", p->u.c.v.p); break;
case F:
{ // JDC: added this to get inline floats
floatint_t temp;
temp.f = p->u.c.v.d;
p->x.name = stringf("%U", temp.ui );
}
break;// JDC: added this
default: assert(0);
}
else if (p->scope >= LOCAL && p->sclass == STATIC)
p->x.name = stringf("$%d", genlabel(1));
else if (p->scope == LABELS || p->generated)
p->x.name = stringf("$%s", p->name);
else
p->x.name = p->name;
}
static void dumptree(Node p) {
switch (specific(p->op)) {
case ASGN+B:
assert(p->kids[0]);
assert(p->kids[1]);
assert(p->syms[0]);
dumptree(p->kids[0]);
dumptree(p->kids[1]);
print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.u);
return;
case RET+V:
assert(!p->kids[0]);
assert(!p->kids[1]);
print("%s\n", opname(p->op));
return;
}
switch (generic(p->op)) {
case CNST: case ADDRG: case ADDRF: case ADDRL: case LABEL:
assert(!p->kids[0]);
assert(!p->kids[1]);
assert(p->syms[0] && p->syms[0]->x.name);
print("%s %s\n", opname(p->op), p->syms[0]->x.name);
return;
case CVF: case CVI: case CVP: case CVU:
assert(p->kids[0]);
assert(!p->kids[1]);
assert(p->syms[0]);
dumptree(p->kids[0]);
print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.i);
return;
case ARG: case BCOM: case NEG: case INDIR: case JUMP: case RET:
assert(p->kids[0]);
assert(!p->kids[1]);
dumptree(p->kids[0]);
print("%s\n", opname(p->op));
return;
case CALL:
assert(p->kids[0]);
assert(!p->kids[1]);
assert(optype(p->op) != B);
dumptree(p->kids[0]);
print("%s\n", opname(p->op));
if ( !p->count ) { printf("pop\n"); }; // JDC
return;
case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH:
case ADD: case SUB: case DIV: case MUL: case MOD:
assert(p->kids[0]);
assert(p->kids[1]);
dumptree(p->kids[0]);
dumptree(p->kids[1]);
print("%s\n", opname(p->op));
return;
case EQ: case NE: case GT: case GE: case LE: case LT:
assert(p->kids[0]);
assert(p->kids[1]);
assert(p->syms[0]);
assert(p->syms[0]->x.name);
dumptree(p->kids[0]);
dumptree(p->kids[1]);
print("%s %s\n", opname(p->op), p->syms[0]->x.name);
return;
}
assert(0);
}
static void I(emit)(Node p) {
for (; p; p = p->link)
dumptree(p);
}
static void I(export)(Symbol p) {
print("export %s\n", p->x.name);
}
static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
int i;
(*IR->segment)(CODE);
offset = 0;
for (i = 0; caller[i] && callee[i]; i++) {
offset = roundup(offset, caller[i]->type->align);
caller[i]->x.name = callee[i]->x.name = stringf("%d", offset);
caller[i]->x.offset = callee[i]->x.offset = offset;
offset += caller[i]->type->size;
}
maxargoffset = maxoffset = argoffset = offset = 0;
gencode(caller, callee);
print("proc %s %d %d\n", f->x.name, maxoffset, maxargoffset);
emitcode();
print("endproc %s %d %d\n", f->x.name, maxoffset, maxargoffset);
}
static void gen02(Node p) {
assert(p);
if (generic(p->op) == ARG) {
assert(p->syms[0]);
argoffset += (p->syms[0]->u.c.v.i < 4 ? 4 : p->syms[0]->u.c.v.i);
} else if (generic(p->op) == CALL) {
maxargoffset = (argoffset > maxargoffset ? argoffset : maxargoffset);
argoffset = 0;
}
}
static void gen01(Node p) {
if (p) {
gen01(p->kids[0]);
gen01(p->kids[1]);
gen02(p);
}
}
static Node I(gen)(Node p) {
Node q;
assert(p);
for (q = p; q; q = q->link)
gen01(q);
return p;
}
static void I(global)(Symbol p) {
print("align %d\n", p->type->align > 4 ? 4 : p->type->align);
print("LABELV %s\n", p->x.name);
}
static void I(import)(Symbol p) {
print("import %s\n", p->x.name);
}
static void I(local)(Symbol p) {
offset = roundup(offset, p->type->align);
p->x.name = stringf("%d", offset);
p->x.offset = offset;
offset += p->type->size;
}
static void I(progbeg)(int argc, char *argv[]) {}
static void I(progend)(void) {}
static void I(space)(int n) {
print("skip %d\n", n);
}
//========================================================
// JDC: hacked up to get interleaved source lines in asm code
static char *sourceFile;
static char *sourcePtr;
static int sourceLine;
static int filelength( FILE *f ) {
int pos;
int end;
pos = ftell (f);
fseek (f, 0, SEEK_END);
end = ftell (f);
fseek (f, pos, SEEK_SET);
return end;
}
static void LoadSourceFile( const char *filename ) {
FILE *f;
int length;
f = fopen( filename, "r" );
if ( !f ) {
print( ";couldn't open %s\n", filename );
sourceFile = NULL;
return;
}
length = filelength( f );
sourceFile = malloc( length + 1 );
if ( sourceFile ) {
fread( sourceFile, length, 1, f );
sourceFile[length] = 0;
}
fclose( f );
sourceLine = 1;
sourcePtr = sourceFile;
}
static void PrintToSourceLine( int line ) {
int c;
if ( !sourceFile ) {
return;
}
while ( sourceLine <= line ) {
int i;
for ( i = 0 ; sourcePtr[i] && sourcePtr[i] != '\n' ; i++ ) {
}
c = sourcePtr[i];
if ( c == '\n' ) {
sourcePtr[i] = 0;
}
print( ";%d:%s\n", sourceLine, sourcePtr );
if ( c == 0 ) {
sourcePtr += i; // end of file
} else {
sourcePtr += i+1;
}
sourceLine++;
}
}
static void I(stabline)(Coordinate *cp) {
static char *prevfile;
static int prevline;
if (cp->file && (prevfile == NULL || strcmp(prevfile, cp->file) != 0)) {
print("file \"%s\"\n", prevfile = cp->file);
prevline = 0;
if ( sourceFile ) {
free( sourceFile );
sourceFile = NULL;
}
// load the new source file
LoadSourceFile( cp->file );
}
if (cp->y != prevline) {
print("line %d\n", prevline = cp->y);
PrintToSourceLine( cp->y );
}
}
//========================================================
#define b_blockbeg blockbeg
#define b_blockend blockend
Interface bytecodeIR = {
{1, 1, 0}, /* char */
{2, 2, 0}, /* short */
{4, 4, 0}, /* int */
{4, 4, 0}, /* long */
{4, 4, 0}, /* long long */
{4, 4, 0}, /* float */ // JDC: use inline floats
{4, 4, 0}, /* double */ // JDC: don't ever emit 8 byte double code
{4, 4, 0}, /* long double */ // JDC: don't ever emit 8 byte double code
{4, 4, 0}, /* T* */
{0, 4, 0}, /* struct */
0, /* little_endian */
0, /* mulops_calls */
0, /* wants_callb */
0, /* wants_argb */
1, /* left_to_right */
0, /* wants_dag */
0, /* unsigned_char */
I(address),
I(blockbeg),
I(blockend),
I(defaddress),
I(defconst),
I(defstring),
I(defsymbol),
I(emit),
I(export),
I(function),
I(gen),
I(global),
I(import),
I(local),
I(progbeg),
I(progend),
I(segment),
I(space),
0, /* I(stabblock) */
0, /* I(stabend) */
0, /* I(stabfend) */
0, /* I(stabinit) */
I(stabline),
0, /* I(stabsym) */
0, /* I(stabtype) */
};

View File

@@ -1,729 +0,0 @@
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#define NEW(p,a) ((p) = allocate(sizeof *(p), (a)))
#define NEW0(p,a) memset(NEW((p),(a)), 0, sizeof *(p))
#define isaddrop(op) (specific(op)==ADDRG+P || specific(op)==ADDRL+P \
|| specific(op)==ADDRF+P)
#define MAXLINE 512
#define BUFSIZE 4096
#define istypename(t,tsym) (kind[t] == CHAR \
|| (t == ID && tsym && tsym->sclass == TYPEDEF))
#define sizeop(n) ((n)<<10)
#define generic(op) ((op)&0x3F0)
#define specific(op) ((op)&0x3FF)
#define opindex(op) (((op)>>4)&0x3F)
#define opkind(op) ((op)&~0x3F0)
#define opsize(op) ((op)>>10)
#define optype(op) ((op)&0xF)
#ifdef __LCC__
#ifndef __STDC__
#define __STDC__
#endif
#endif
#define NELEMS(a) ((int)(sizeof (a)/sizeof ((a)[0])))
#undef roundup
#define roundup(x,n) (((x)+((n)-1))&(~((n)-1)))
#define mkop(op,ty) (specific((op) + ttob(ty)))
#define extend(x,ty) ((x)&(1<<(8*(ty)->size-1)) ? (x)|((~0UL)<<(8*(ty)->size-1)) : (x)&ones(8*(ty)->size))
#define ones(n) ((n)>=8*sizeof (unsigned long) ? ~0UL : ~((~0UL)<<(n)))
#define isqual(t) ((t)->op >= CONST)
#define unqual(t) (isqual(t) ? (t)->type : (t))
#define isvolatile(t) ((t)->op == VOLATILE \
|| (t)->op == CONST+VOLATILE)
#define isconst(t) ((t)->op == CONST \
|| (t)->op == CONST+VOLATILE)
#define isarray(t) (unqual(t)->op == ARRAY)
#define isstruct(t) (unqual(t)->op == STRUCT \
|| unqual(t)->op == UNION)
#define isunion(t) (unqual(t)->op == UNION)
#define isfunc(t) (unqual(t)->op == FUNCTION)
#define isptr(t) (unqual(t)->op == POINTER)
#define ischar(t) ((t)->size == 1 && isint(t))
#define isint(t) (unqual(t)->op == INT \
|| unqual(t)->op == UNSIGNED)
#define isfloat(t) (unqual(t)->op == FLOAT)
#define isarith(t) (unqual(t)->op <= UNSIGNED)
#define isunsigned(t) (unqual(t)->op == UNSIGNED)
#define isscalar(t) (unqual(t)->op <= POINTER \
|| unqual(t)->op == ENUM)
#define isenum(t) (unqual(t)->op == ENUM)
#define fieldsize(p) (p)->bitsize
#define fieldright(p) ((p)->lsb - 1)
#define fieldleft(p) (8*(p)->type->size - \
fieldsize(p) - fieldright(p))
#define fieldmask(p) (~(~(unsigned)0<<fieldsize(p)))
typedef struct node *Node;
typedef struct list *List;
typedef struct code *Code;
typedef struct swtch *Swtch;
typedef struct symbol *Symbol;
typedef struct coord {
char *file;
unsigned x, y;
} Coordinate;
typedef struct table *Table;
typedef union value {
long i;
unsigned long u;
double d;
void *p;
void (*g)(void);
} Value;
typedef struct tree *Tree;
typedef struct type *Type;
typedef struct field *Field;
typedef struct {
unsigned printed:1;
unsigned marked;
unsigned short typeno;
void *xt;
} Xtype;
typedef union {
float f;
int i;
unsigned int ui;
} floatint_t;
#include "config.h"
typedef struct metrics {
unsigned char size, align, outofline;
} Metrics;
typedef struct interface {
Metrics charmetric;
Metrics shortmetric;
Metrics intmetric;
Metrics longmetric;
Metrics longlongmetric;
Metrics floatmetric;
Metrics doublemetric;
Metrics longdoublemetric;
Metrics ptrmetric;
Metrics structmetric;
unsigned little_endian:1;
unsigned mulops_calls:1;
unsigned wants_callb:1;
unsigned wants_argb:1;
unsigned left_to_right:1;
unsigned wants_dag:1;
unsigned unsigned_char:1;
void (*address)(Symbol p, Symbol q, long n);
void (*blockbeg)(Env *);
void (*blockend)(Env *);
void (*defaddress)(Symbol);
void (*defconst) (int suffix, int size, Value v);
void (*defstring)(int n, char *s);
void (*defsymbol)(Symbol);
void (*emit) (Node);
void (*export)(Symbol);
void (*function)(Symbol, Symbol[], Symbol[], int);
Node (*gen) (Node);
void (*global)(Symbol);
void (*import)(Symbol);
void (*local)(Symbol);
void (*progbeg)(int argc, char *argv[]);
void (*progend)(void);
void (*segment)(int);
void (*space)(int);
void (*stabblock)(int, int, Symbol*);
void (*stabend) (Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *);
void (*stabfend) (Symbol, int);
void (*stabinit) (char *, int, char *[]);
void (*stabline) (Coordinate *);
void (*stabsym) (Symbol);
void (*stabtype) (Symbol);
Xinterface x;
} Interface;
typedef struct binding {
char *name;
Interface *ir;
} Binding;
extern Binding bindings[];
extern Interface *IR;
typedef struct {
List blockentry;
List blockexit;
List entry;
List exit;
List returns;
List points;
List calls;
List end;
} Events;
enum {
#define xx(a,b,c,d,e,f,g) a=b,
#define yy(a,b,c,d,e,f,g)
#include "token.h"
LAST
};
struct node {
short op;
short count;
Symbol syms[3];
Node kids[2];
Node link;
Xnode x;
};
enum {
F=FLOAT,
I=INT,
U=UNSIGNED,
P=POINTER,
V=VOID,
B=STRUCT
};
#define gop(name,value) name=value<<4,
#define op(name,type,sizes)
enum { gop(CNST,1)
op(CNST,F,fdx)
op(CNST,I,csilh)
op(CNST,P,p)
op(CNST,U,csilh)
gop(ARG,2)
op(ARG,B,-)
op(ARG,F,fdx)
op(ARG,I,ilh)
op(ARG,P,p)
op(ARG,U,ilh)
gop(ASGN,3)
op(ASGN,B,-)
op(ASGN,F,fdx)
op(ASGN,I,csilh)
op(ASGN,P,p)
op(ASGN,U,csilh)
gop(INDIR,4)
op(INDIR,B,-)
op(INDIR,F,fdx)
op(INDIR,I,csilh)
op(INDIR,P,p)
op(INDIR,U,csilh)
gop(CVF,7)
op(CVF,F,fdx)
op(CVF,I,ilh)
gop(CVI,8)
op(CVI,F,fdx)
op(CVI,I,csilh)
op(CVI,U,csilhp)
gop(CVP,9)
op(CVP,U,p)
gop(CVU,11)
op(CVU,I,csilh)
op(CVU,P,p)
op(CVU,U,csilh)
gop(NEG,12)
op(NEG,F,fdx)
op(NEG,I,ilh)
gop(CALL,13)
op(CALL,B,-)
op(CALL,F,fdx)
op(CALL,I,ilh)
op(CALL,P,p)
op(CALL,U,ilh)
op(CALL,V,-)
gop(RET,15)
op(RET,F,fdx)
op(RET,I,ilh)
op(RET,P,p)
op(RET,U,ilh)
op(RET,V,-)
gop(ADDRG,16)
op(ADDRG,P,p)
gop(ADDRF,17)
op(ADDRF,P,p)
gop(ADDRL,18)
op(ADDRL,P,p)
gop(ADD,19)
op(ADD,F,fdx)
op(ADD,I,ilh)
op(ADD,P,p)
op(ADD,U,ilhp)
gop(SUB,20)
op(SUB,F,fdx)
op(SUB,I,ilh)
op(SUB,P,p)
op(SUB,U,ilhp)
gop(LSH,21)
op(LSH,I,ilh)
op(LSH,U,ilh)
gop(MOD,22)
op(MOD,I,ilh)
op(MOD,U,ilh)
gop(RSH,23)
op(RSH,I,ilh)
op(RSH,U,ilh)
gop(BAND,24)
op(BAND,I,ilh)
op(BAND,U,ilh)
gop(BCOM,25)
op(BCOM,I,ilh)
op(BCOM,U,ilh)
gop(BOR,26)
op(BOR,I,ilh)
op(BOR,U,ilh)
gop(BXOR,27)
op(BXOR,I,ilh)
op(BXOR,U,ilh)
gop(DIV,28)
op(DIV,F,fdx)
op(DIV,I,ilh)
op(DIV,U,ilh)
gop(MUL,29)
op(MUL,F,fdx)
op(MUL,I,ilh)
op(MUL,U,ilh)
gop(EQ,30)
op(EQ,F,fdx)
op(EQ,I,ilh)
op(EQ,U,ilhp)
gop(GE,31)
op(GE,F,fdx)
op(GE,I,ilh)
op(GE,U,ilhp)
gop(GT,32)
op(GT,F,fdx)
op(GT,I,ilh)
op(GT,U,ilhp)
gop(LE,33)
op(LE,F,fdx)
op(LE,I,ilh)
op(LE,U,ilhp)
gop(LT,34)
op(LT,F,fdx)
op(LT,I,ilh)
op(LT,U,ilhp)
gop(NE,35)
op(NE,F,fdx)
op(NE,I,ilh)
op(NE,U,ilhp)
gop(JUMP,36)
op(JUMP,V,-)
gop(LABEL,37)
op(LABEL,V,-)
gop(LOAD,14)
op(LOAD,B,-)
op(LOAD,F,fdx)
op(LOAD,I,csilh)
op(LOAD,P,p)
op(LOAD,U,csilhp) LASTOP };
#undef gop
#undef op
enum { CODE=1, BSS, DATA, LIT };
enum { PERM=0, FUNC, STMT };
struct list {
void *x;
List link;
};
struct code {
enum { Blockbeg, Blockend, Local, Address, Defpoint,
Label, Start, Gen, Jump, Switch
} kind;
Code prev, next;
union {
struct {
int level;
Symbol *locals;
Table identifiers, types;
Env x;
} block;
Code begin;
Symbol var;
struct {
Symbol sym;
Symbol base;
long offset;
} addr;
struct {
Coordinate src;
int point;
} point;
Node forest;
struct {
Symbol sym;
Symbol table;
Symbol deflab;
int size;
long *values;
Symbol *labels;
} swtch;
} u;
};
struct swtch {
Symbol sym;
int lab;
Symbol deflab;
int ncases;
int size;
long *values;
Symbol *labels;
};
struct symbol {
char *name;
int scope;
Coordinate src;
Symbol up;
List uses;
int sclass;
unsigned structarg:1;
unsigned addressed:1;
unsigned computed:1;
unsigned temporary:1;
unsigned generated:1;
unsigned defined:1;
Type type;
float ref;
union {
struct {
int label;
Symbol equatedto;
} l;
struct {
unsigned cfields:1;
unsigned vfields:1;
Table ftab; /* omit */
Field flist;
} s;
int value;
Symbol *idlist;
struct {
Value min, max;
} limits;
struct {
Value v;
Symbol loc;
} c;
struct {
Coordinate pt;
int label;
int ncalls;
Symbol *callee;
} f;
int seg;
Symbol alias;
struct {
Node cse;
int replace;
Symbol next;
} t;
} u;
Xsymbol x;
};
enum { CONSTANTS=1, LABELS, GLOBAL, PARAM, LOCAL };
struct tree {
int op;
Type type;
Tree kids[2];
Node node;
union {
Value v;
Symbol sym;
Field field;
} u;
};
enum {
AND=38<<4,
NOT=39<<4,
OR=40<<4,
COND=41<<4,
RIGHT=42<<4,
FIELD=43<<4
};
struct type {
int op;
Type type;
int align;
int size;
union {
Symbol sym;
struct {
unsigned oldstyle:1;
Type *proto;
} f;
} u;
Xtype x;
};
struct field {
char *name;
Type type;
int offset;
short bitsize;
short lsb;
Field link;
};
extern int assignargs;
extern int prunetemps;
extern int nodecount;
extern Symbol cfunc;
extern Symbol retv;
extern Tree (*optree[])(int, Tree, Tree);
extern char kind[];
extern int errcnt;
extern int errlimit;
extern int wflag;
extern Events events;
extern float refinc;
extern unsigned char *cp;
extern unsigned char *limit;
extern char *firstfile;
extern char *file;
extern char *line;
extern int lineno;
extern int t;
extern char *token;
extern Symbol tsym;
extern Coordinate src;
extern int Aflag;
extern int Pflag;
extern Symbol YYnull;
extern Symbol YYcheck;
extern int glevel;
extern int xref;
extern int ncalled;
extern int npoints;
extern int needconst;
extern int explicitCast;
extern struct code codehead;
extern Code codelist;
extern Table stmtlabs;
extern float density;
extern Table constants;
extern Table externals;
extern Table globals;
extern Table identifiers;
extern Table labels;
extern Table types;
extern int level;
extern List loci, symbols;
extern List symbols;
extern int where;
extern Type chartype;
extern Type doubletype;
extern Type floattype;
extern Type inttype;
extern Type longdouble;
extern Type longtype;
extern Type longlong;
extern Type shorttype;
extern Type signedchar;
extern Type unsignedchar;
extern Type unsignedlonglong;
extern Type unsignedlong;
extern Type unsignedshort;
extern Type unsignedtype;
extern Type charptype;
extern Type funcptype;
extern Type voidptype;
extern Type voidtype;
extern Type unsignedptr;
extern Type signedptr;
extern Type widechar;
extern void *allocate(unsigned long n, unsigned a);
extern void deallocate(unsigned a);
extern void *newarray(unsigned long m, unsigned long n, unsigned a);
extern void walk(Tree e, int tlab, int flab);
extern Node listnodes(Tree e, int tlab, int flab);
extern Node newnode(int op, Node left, Node right, Symbol p);
extern Tree cvtconst(Tree);
extern void printdag(Node, int);
extern void compound(int, Swtch, int);
extern void defglobal(Symbol, int);
extern void finalize(void);
extern void program(void);
extern Tree vcall(Symbol func, Type ty, ...);
extern Tree addrof(Tree);
extern Tree asgn(Symbol, Tree);
extern Tree asgntree(int, Tree, Tree);
extern Type assign(Type, Tree);
extern Tree bittree(int, Tree, Tree);
extern Tree call(Tree, Type, Coordinate);
extern Tree calltree(Tree, Type, Tree, Symbol);
extern Tree condtree(Tree, Tree, Tree);
extern Tree cnsttree(Type, ...);
extern Tree consttree(unsigned int, Type);
extern Tree eqtree(int, Tree, Tree);
extern int iscallb(Tree);
extern Tree shtree(int, Tree, Tree);
extern void typeerror(int, Tree, Tree);
extern void test(int tok, char set[]);
extern void expect(int tok);
extern void skipto(int tok, char set[]);
extern void error(const char *, ...);
extern int fatal(const char *, const char *, int);
extern void warning(const char *, ...);
typedef void (*Apply)(void *, void *, void *);
extern void attach(Apply, void *, List *);
extern void apply(List event, void *arg1, void *arg2);
extern Tree retype(Tree p, Type ty);
extern Tree rightkid(Tree p);
extern int hascall(Tree p);
extern Type binary(Type, Type);
extern Tree cast(Tree, Type);
extern Tree cond(Tree);
extern Tree expr0(int);
extern Tree expr(int);
extern Tree expr1(int);
extern Tree field(Tree, const char *);
extern char *funcname(Tree);
extern Tree idtree(Symbol);
extern Tree incr(int, Tree, Tree);
extern Tree lvalue(Tree);
extern Tree nullcall(Type, Symbol, Tree, Tree);
extern Tree pointer(Tree);
extern Tree rvalue(Tree);
extern Tree value(Tree);
extern void defpointer(Symbol);
extern Type initializer(Type, int);
extern void swtoseg(int);
extern void input_init(int, char *[]);
extern void fillbuf(void);
extern void nextline(void);
extern int getchr(void);
extern int gettok(void);
extern void emitcode(void);
extern void gencode (Symbol[], Symbol[]);
extern void fprint(FILE *f, const char *fmt, ...);
extern char *stringf(const char *, ...);
extern void check(Node);
extern void print(const char *, ...);
extern List append(void *x, List list);
extern int length(List list);
extern void *ltov (List *list, unsigned a);
extern void init(int, char *[]);
extern Type typename(void);
extern void checklab(Symbol p, void *cl);
extern Type enumdcl(void);
extern void main_init(int, char *[]);
extern int main(int, char *[]);
extern void vfprint(FILE *, char *, const char *, va_list);
extern int process(char *);
extern int findfunc(char *, char *);
extern int findcount(char *, int, int);
extern Tree constexpr(int);
extern int intexpr(int, int);
extern Tree simplify(int, Type, Tree, Tree);
extern int ispow2(unsigned long u);
extern int reachable(int);
extern void addlocal(Symbol);
extern void branch(int);
extern Code code(int);
extern void definelab(int);
extern void definept(Coordinate *);
extern void equatelab(Symbol, Symbol);
extern Node jump(int);
extern void retcode(Tree);
extern void statement(int, Swtch, int);
extern void swcode(Swtch, int *, int, int);
extern void swgen(Swtch);
extern char * string(const char *str);
extern char *stringn(const char *str, int len);
extern char *stringd(long n);
extern Symbol relocate(const char *name, Table src, Table dst);
extern void use(Symbol p, Coordinate src);
extern void locus(Table tp, Coordinate *cp);
extern Symbol allsymbols(Table);
extern Symbol constant(Type, Value);
extern void enterscope(void);
extern void exitscope(void);
extern Symbol findlabel(int);
extern Symbol findtype(Type);
extern void foreach(Table, int, void (*)(Symbol, void *), void *);
extern Symbol genident(int, Type, int);
extern int genlabel(int);
extern Symbol install(const char *, Table *, int, int);
extern Symbol intconst(int);
extern Symbol lookup(const char *, Table);
extern Symbol mkstr(char *);
extern Symbol mksymbol(int, const char *, Type);
extern Symbol newtemp(int, int, int);
extern Table table(Table, int);
extern Symbol temporary(int, Type);
extern char *vtoa(Type, Value);
extern int nodeid(Tree);
extern char *opname(int);
extern int *printed(int);
extern void printtree(Tree, int);
extern Tree root(Tree);
extern Tree texpr(Tree (*)(int), int, int);
extern Tree tree(int, Type, Tree, Tree);
extern void type_init(int, char *[]);
extern Type signedint(Type);
extern int hasproto(Type);
extern void outtype(Type, FILE *);
extern void printdecl (Symbol p, Type ty);
extern void printproto(Symbol p, Symbol args[]);
extern char *typestring(Type ty, char *id);
extern Field fieldref(const char *name, Type ty);
extern Type array(Type, int, int);
extern Type atop(Type);
extern Type btot(int, int);
extern Type compose(Type, Type);
extern Type deref(Type);
extern int eqtype(Type, Type, int);
extern Field fieldlist(Type);
extern Type freturn(Type);
extern Type ftype(Type, Type);
extern Type func(Type, Type *, int);
extern Field newfield(char *, Type, Type);
extern Type newstruct(int, char *);
extern void printtype(Type, int);
extern Type promote(Type);
extern Type ptr(Type);
extern Type qual(int, Type);
extern void rmtypes(int);
extern int ttob(Type);
extern int variadic(Type);

View File

@@ -1,102 +0,0 @@
typedef struct {
unsigned char max_unaligned_load;
Symbol (*rmap)(int);
void (*blkfetch)(int size, int off, int reg, int tmp);
void (*blkstore)(int size, int off, int reg, int tmp);
void (*blkloop)(int dreg, int doff,
int sreg, int soff,
int size, int tmps[]);
void (*_label)(Node);
int (*_rule)(void*, int);
short **_nts;
void (*_kids)(Node, int, Node*);
char **_string;
char **_templates;
char *_isinstruction;
char **_ntname;
void (*emit2)(Node);
void (*doarg)(Node);
void (*target)(Node);
void (*clobber)(Node);
} Xinterface;
extern int askregvar(Symbol, Symbol);
extern void blkcopy(int, int, int, int, int, int[]);
extern int getregnum(Node);
extern int mayrecalc(Node);
extern int mkactual(int, int);
extern void mkauto(Symbol);
extern Symbol mkreg(char *, int, int, int);
extern Symbol mkwildcard(Symbol *);
extern int move(Node);
extern int notarget(Node);
extern void parseflags(int, char **);
extern int range(Node, int, int);
extern unsigned regloc(Symbol); /* omit */
extern void rtarget(Node, int, Symbol);
extern void setreg(Node, Symbol);
extern void spill(unsigned, int, Node);
extern int widens(Node);
extern int argoffset, maxargoffset;
extern int bflag, dflag;
extern int dalign, salign;
extern int framesize;
extern unsigned freemask[], usedmask[];
extern int offset, maxoffset;
extern int swap;
extern unsigned tmask[], vmask[];
typedef struct {
unsigned listed:1;
unsigned registered:1;
unsigned emitted:1;
unsigned copy:1;
unsigned equatable:1;
unsigned spills:1;
unsigned mayrecalc:1;
void *state;
short inst;
Node kids[3];
Node prev, next;
Node prevuse;
short argno;
} Xnode;
typedef struct {
Symbol vbl;
short set;
short number;
unsigned mask;
} *Regnode;
enum { IREG=0, FREG=1 };
typedef struct {
char *name;
unsigned int eaddr; /* omit */
int offset;
Node lastuse;
int usecount;
Regnode regnode;
Symbol *wildcard;
} Xsymbol;
enum { RX=2 };
typedef struct {
int offset;
unsigned freemask[2];
} Env;
#define LBURG_MAX SHRT_MAX
enum { VREG=(44<<4) };
/* Exported for the front end */
extern void blockbeg(Env *);
extern void blockend(Env *);
extern void emit(Node);
extern Node gen(Node);
extern unsigned emitbin(Node, int);
#ifdef NDEBUG
#define debug(x) (void)0
#else
#define debug(x) (void)(dflag&&((x),0))
#endif

View File

@@ -1,736 +0,0 @@
#include "c.h"
#define iscall(op) (generic(op) == CALL \
|| (IR->mulops_calls \
&& (generic(op)==DIV||generic(op)==MOD||generic(op)==MUL) \
&& ( optype(op)==U || optype(op)==I)))
static Node forest;
static struct dag {
struct node node;
struct dag *hlink;
} *buckets[16];
int nodecount;
static Tree firstarg;
int assignargs = 1;
int prunetemps = -1;
static Node *tail;
static int depth = 0;
static Node replace(Node);
static Node prune(Node);
static Node asgnnode(Symbol, Node);
static struct dag *dagnode(int, Node, Node, Symbol);
static Symbol equated(Symbol);
static void fixup(Node);
static void labelnode(int);
static void list(Node);
static void kill(Symbol);
static Node node(int, Node, Node, Symbol);
static void printdag1(Node, int, int);
static void printnode(Node, int, int);
static void reset(void);
static Node tmpnode(Node);
static void typestab(Symbol, void *);
static Node undag(Node);
static Node visit(Node, int);
static void unlist(void);
void walk(Tree tp, int tlab, int flab) {
listnodes(tp, tlab, flab);
if (forest) {
Node list = forest->link;
forest->link = NULL;
if (!IR->wants_dag)
list = undag(list);
code(Gen)->u.forest = list;
forest = NULL;
}
reset();
deallocate(STMT);
}
static Node node(int op, Node l, Node r, Symbol sym) {
int i;
struct dag *p;
i = (opindex(op)^((unsigned long)sym>>2))&(NELEMS(buckets)-1);
for (p = buckets[i]; p; p = p->hlink)
if (p->node.op == op && p->node.syms[0] == sym
&& p->node.kids[0] == l && p->node.kids[1] == r)
return &p->node;
p = dagnode(op, l, r, sym);
p->hlink = buckets[i];
buckets[i] = p;
++nodecount;
return &p->node;
}
static struct dag *dagnode(int op, Node l, Node r, Symbol sym) {
struct dag *p;
NEW0(p, FUNC);
p->node.op = op;
if ((p->node.kids[0] = l) != NULL)
++l->count;
if ((p->node.kids[1] = r) != NULL)
++r->count;
p->node.syms[0] = sym;
return p;
}
Node newnode(int op, Node l, Node r, Symbol sym) {
return &dagnode(op, l, r, sym)->node;
}
static void kill(Symbol p) {
int i;
struct dag **q;
for (i = 0; i < NELEMS(buckets); i++)
for (q = &buckets[i]; *q; )
if (generic((*q)->node.op) == INDIR &&
(!isaddrop((*q)->node.kids[0]->op)
|| (*q)->node.kids[0]->syms[0] == p)) {
*q = (*q)->hlink;
--nodecount;
} else
q = &(*q)->hlink;
}
static void reset(void) {
if (nodecount > 0)
memset(buckets, 0, sizeof buckets);
nodecount = 0;
}
Node listnodes(Tree tp, int tlab, int flab) {
Node p = NULL, l, r;
int op;
assert(tlab || flab || (tlab == 0 && flab == 0));
if (tp == NULL)
return NULL;
if (tp->node)
return tp->node;
op = tp->op + sizeop(tp->type->size);
switch (generic(tp->op)) {
case AND: { if (depth++ == 0) reset();
if (flab) {
listnodes(tp->kids[0], 0, flab);
listnodes(tp->kids[1], 0, flab);
} else {
listnodes(tp->kids[0], 0, flab = genlabel(1));
listnodes(tp->kids[1], tlab, 0);
labelnode(flab);
}
depth--; } break;
case OR: { if (depth++ == 0)
reset();
if (tlab) {
listnodes(tp->kids[0], tlab, 0);
listnodes(tp->kids[1], tlab, 0);
} else {
tlab = genlabel(1);
listnodes(tp->kids[0], tlab, 0);
listnodes(tp->kids[1], 0, flab);
labelnode(tlab);
}
depth--;
} break;
case NOT: { return listnodes(tp->kids[0], flab, tlab); }
case COND: { Tree q = tp->kids[1];
assert(tlab == 0 && flab == 0);
if (tp->u.sym)
addlocal(tp->u.sym);
flab = genlabel(2);
listnodes(tp->kids[0], 0, flab);
assert(q && q->op == RIGHT);
reset();
listnodes(q->kids[0], 0, 0);
if (forest->op == LABEL+V) {
equatelab(forest->syms[0], findlabel(flab + 1));
unlist();
}
list(jump(flab + 1));
labelnode(flab);
listnodes(q->kids[1], 0, 0);
if (forest->op == LABEL+V) {
equatelab(forest->syms[0], findlabel(flab + 1));
unlist();
}
labelnode(flab + 1);
if (tp->u.sym)
p = listnodes(idtree(tp->u.sym), 0, 0); } break;
case CNST: { Type ty = unqual(tp->type);
assert(ty->u.sym);
if (tlab || flab) {
assert(ty == inttype);
if (tlab && tp->u.v.i != 0)
list(jump(tlab));
else if (flab && tp->u.v.i == 0)
list(jump(flab));
}
else if (ty->u.sym->addressed)
p = listnodes(cvtconst(tp), 0, 0);
else
p = node(op, NULL, NULL, constant(ty, tp->u.v)); } break;
case RIGHT: { if ( tp->kids[0] && tp->kids[1]
&& generic(tp->kids[1]->op) == ASGN
&& ((generic(tp->kids[0]->op) == INDIR
&& tp->kids[0]->kids[0] == tp->kids[1]->kids[0])
|| (tp->kids[0]->op == FIELD
&& tp->kids[0] == tp->kids[1]->kids[0]))) {
assert(tlab == 0 && flab == 0);
if (generic(tp->kids[0]->op) == INDIR) {
p = listnodes(tp->kids[0], 0, 0);
list(p);
listnodes(tp->kids[1], 0, 0);
}
else {
assert(generic(tp->kids[0]->kids[0]->op) == INDIR);
list(listnodes(tp->kids[0]->kids[0], 0, 0));
p = listnodes(tp->kids[0], 0, 0);
listnodes(tp->kids[1], 0, 0);
}
} else if (tp->kids[1]) {
listnodes(tp->kids[0], 0, 0);
p = listnodes(tp->kids[1], tlab, flab);
} else
p = listnodes(tp->kids[0], tlab, flab); } break;
case JUMP: { assert(tlab == 0 && flab == 0);
assert(tp->u.sym == 0);
assert(tp->kids[0]);
l = listnodes(tp->kids[0], 0, 0);
list(newnode(JUMP+V, l, NULL, NULL));
reset(); } break;
case CALL: { Tree save = firstarg;
firstarg = NULL;
assert(tlab == 0 && flab == 0);
if (tp->op == CALL+B && !IR->wants_callb) {
Tree arg0 = tree(ARG+P, tp->kids[1]->type,
tp->kids[1], NULL);
if (IR->left_to_right)
firstarg = arg0;
l = listnodes(tp->kids[0], 0, 0);
if (!IR->left_to_right || firstarg) {
firstarg = NULL;
listnodes(arg0, 0, 0);
}
p = newnode(CALL+V, l, NULL, NULL);
} else {
l = listnodes(tp->kids[0], 0, 0);
r = listnodes(tp->kids[1], 0, 0);
p = newnode(tp->op == CALL+B ? tp->op : op, l, r, NULL);
}
NEW0(p->syms[0], FUNC);
assert(isptr(tp->kids[0]->type));
assert(isfunc(tp->kids[0]->type->type));
p->syms[0]->type = tp->kids[0]->type->type;
list(p);
reset();
cfunc->u.f.ncalls++;
firstarg = save;
} break;
case ARG: { assert(tlab == 0 && flab == 0);
if (IR->left_to_right)
listnodes(tp->kids[1], 0, 0);
if (firstarg) {
Tree arg = firstarg;
firstarg = NULL;
listnodes(arg, 0, 0);
}
l = listnodes(tp->kids[0], 0, 0);
list(newnode(tp->op == ARG+B ? tp->op : op, l, NULL, NULL));
forest->syms[0] = intconst(tp->type->size);
forest->syms[1] = intconst(tp->type->align);
if (!IR->left_to_right)
listnodes(tp->kids[1], 0, 0); } break;
case EQ: case NE: case GT: case GE: case LE:
case LT: { assert(tp->u.sym == 0);
assert(errcnt || tlab || flab);
l = listnodes(tp->kids[0], 0, 0);
r = listnodes(tp->kids[1], 0, 0);
assert(errcnt || opkind(l->op) == opkind(r->op));
assert(errcnt || optype(op) == optype(l->op));
if (tlab)
assert(flab == 0),
list(newnode(generic(tp->op) + opkind(l->op), l, r, findlabel(tlab)));
else if (flab) {
switch (generic(tp->op)) {
case EQ: op = NE; break;
case NE: op = EQ; break;
case GT: op = LE; break;
case LT: op = GE; break;
case GE: op = LT; break;
case LE: op = GT; break;
default: assert(0);
}
list(newnode(op + opkind(l->op), l, r, findlabel(flab)));
}
if (forest && forest->syms[0])
forest->syms[0]->ref++; } break;
case ASGN: { assert(tlab == 0 && flab == 0);
if (tp->kids[0]->op == FIELD) {
Tree x = tp->kids[0]->kids[0];
Field f = tp->kids[0]->u.field;
assert(generic(x->op) == INDIR);
reset();
l = listnodes(lvalue(x), 0, 0);
if (fieldsize(f) < 8*f->type->size) {
unsigned int fmask = fieldmask(f);
unsigned int mask = fmask<<fieldright(f);
Tree q = tp->kids[1];
if ((q->op == CNST+I && q->u.v.i == 0)
|| (q->op == CNST+U && q->u.v.u == 0))
q = bittree(BAND, x, cnsttree(unsignedtype, (unsigned long)~mask));
else if ((q->op == CNST+I && (q->u.v.i&fmask) == fmask)
|| (q->op == CNST+U && (q->u.v.u&fmask) == fmask))
q = bittree(BOR, x, cnsttree(unsignedtype, (unsigned long)mask));
else {
listnodes(q, 0, 0);
q = bittree(BOR,
bittree(BAND, rvalue(lvalue(x)),
cnsttree(unsignedtype, (unsigned long)~mask)),
bittree(BAND, shtree(LSH, cast(q, unsignedtype),
cnsttree(unsignedtype, (unsigned long)fieldright(f))),
cnsttree(unsignedtype, (unsigned long)mask)));
}
r = listnodes(q, 0, 0);
op = ASGN + ttob(q->type);
} else {
r = listnodes(tp->kids[1], 0, 0);
op = ASGN + ttob(tp->kids[1]->type);
}
} else {
l = listnodes(tp->kids[0], 0, 0);
r = listnodes(tp->kids[1], 0, 0);
}
list(newnode(tp->op == ASGN+B ? tp->op : op, l, r, NULL));
forest->syms[0] = intconst(tp->kids[1]->type->size);
forest->syms[1] = intconst(tp->kids[1]->type->align);
if (isaddrop(tp->kids[0]->op)
&& !tp->kids[0]->u.sym->computed)
kill(tp->kids[0]->u.sym);
else
reset();
p = listnodes(tp->kids[1], 0, 0); } break;
case BOR: case BAND: case BXOR:
case ADD: case SUB: case RSH:
case LSH: { assert(tlab == 0 && flab == 0);
l = listnodes(tp->kids[0], 0, 0);
r = listnodes(tp->kids[1], 0, 0);
p = node(op, l, r, NULL); } break;
case DIV: case MUL:
case MOD: { assert(tlab == 0 && flab == 0);
l = listnodes(tp->kids[0], 0, 0);
r = listnodes(tp->kids[1], 0, 0);
p = node(op, l, r, NULL);
if (IR->mulops_calls && isint(tp->type)) {
list(p);
cfunc->u.f.ncalls++;
} } break;
case RET: { assert(tlab == 0 && flab == 0);
l = listnodes(tp->kids[0], 0, 0);
list(newnode(op, l, NULL, NULL)); } break;
case CVF: case CVI: case CVP:
case CVU: { assert(tlab == 0 && flab == 0);
assert(optype(tp->kids[0]->op) != optype(tp->op) || tp->kids[0]->type->size != tp->type->size);
l = listnodes(tp->kids[0], 0, 0);
p = node(op, l, NULL, intconst(tp->kids[0]->type->size));
} break;
case BCOM:
case NEG: { assert(tlab == 0 && flab == 0);
l = listnodes(tp->kids[0], 0, 0);
p = node(op, l, NULL, NULL); } break;
case INDIR: { Type ty = tp->kids[0]->type;
assert(tlab == 0 && flab == 0);
l = listnodes(tp->kids[0], 0, 0);
if (isptr(ty))
ty = unqual(ty)->type;
if (isvolatile(ty)
|| (isstruct(ty) && unqual(ty)->u.sym->u.s.vfields))
p = newnode(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL);
else
p = node(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); } break;
case FIELD: { Tree q = tp->kids[0];
if (tp->type == inttype) {
long n = fieldleft(tp->u.field);
q = shtree(RSH,
shtree(LSH, q, cnsttree(inttype, n)),
cnsttree(inttype, n + fieldright(tp->u.field)));
} else if (fieldsize(tp->u.field) < 8*tp->u.field->type->size)
q = bittree(BAND,
shtree(RSH, q, cnsttree(inttype, (long)fieldright(tp->u.field))),
cnsttree(unsignedtype, (unsigned long)fieldmask(tp->u.field)));
assert(tlab == 0 && flab == 0);
p = listnodes(q, 0, 0); } break;
case ADDRG:
case ADDRF: { assert(tlab == 0 && flab == 0);
p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym);
} break;
case ADDRL: { assert(tlab == 0 && flab == 0);
if (tp->u.sym->temporary)
addlocal(tp->u.sym);
p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); } break;
default:assert(0);
}
tp->node = p;
return p;
}
static void list(Node p) {
if (p && p->link == NULL) {
if (forest) {
p->link = forest->link;
forest->link = p;
} else
p->link = p;
forest = p;
}
}
static void labelnode(int lab) {
assert(lab);
if (forest && forest->op == LABEL+V)
equatelab(findlabel(lab), forest->syms[0]);
else
list(newnode(LABEL+V, NULL, NULL, findlabel(lab)));
reset();
}
static void unlist(void) {
Node p;
assert(forest);
assert(forest != forest->link);
p = forest->link;
while (p->link != forest)
p = p->link;
p->link = forest->link;
forest = p;
}
Tree cvtconst(Tree p) {
Symbol q = constant(p->type, p->u.v);
Tree e;
if (q->u.c.loc == NULL)
q->u.c.loc = genident(STATIC, p->type, GLOBAL);
if (isarray(p->type)) {
e = simplify(ADDRG, atop(p->type), NULL, NULL);
e->u.sym = q->u.c.loc;
} else
e = idtree(q->u.c.loc);
return e;
}
void gencode(Symbol caller[], Symbol callee[]) {
Code cp;
Coordinate save;
if (prunetemps == -1)
prunetemps = !IR->wants_dag;
save = src;
if (assignargs) {
int i;
Symbol p, q;
cp = codehead.next->next;
codelist = codehead.next;
for (i = 0; (p = callee[i]) != NULL
&& (q = caller[i]) != NULL; i++)
if (p->sclass != q->sclass || p->type != q->type)
walk(asgn(p, idtree(q)), 0, 0);
codelist->next = cp;
cp->prev = codelist;
}
if (glevel && IR->stabsym) {
int i;
Symbol p, q;
for (i = 0; (p = callee[i]) != NULL
&& (q = caller[i]) != NULL; i++) {
(*IR->stabsym)(p);
if (p->sclass != q->sclass || p->type != q->type)
(*IR->stabsym)(q);
}
swtoseg(CODE);
}
cp = codehead.next;
for ( ; errcnt <= 0 && cp; cp = cp->next)
switch (cp->kind) {
case Address: (*IR->address)(cp->u.addr.sym, cp->u.addr.base,
cp->u.addr.offset); break;
case Blockbeg: {
Symbol *p = cp->u.block.locals;
(*IR->blockbeg)(&cp->u.block.x);
for ( ; *p; p++)
if ((*p)->ref != 0.0)
(*IR->local)(*p);
else if (glevel) (*IR->local)(*p);
}
break;
case Blockend: (*IR->blockend)(&cp->u.begin->u.block.x); break;
case Defpoint: src = cp->u.point.src; break;
case Gen: case Jump:
case Label: if (prunetemps)
cp->u.forest = prune(cp->u.forest);
fixup(cp->u.forest);
cp->u.forest = (*IR->gen)(cp->u.forest); break;
case Local: (*IR->local)(cp->u.var); break;
case Switch: break;
default: assert(0);
}
src = save;
}
static void fixup(Node p) {
for ( ; p; p = p->link)
switch (generic(p->op)) {
case JUMP:
if (specific(p->kids[0]->op) == ADDRG+P)
p->kids[0]->syms[0] =
equated(p->kids[0]->syms[0]);
break;
case LABEL: assert(p->syms[0] == equated(p->syms[0])); break;
case EQ: case GE: case GT: case LE: case LT: case NE:
assert(p->syms[0]);
p->syms[0] = equated(p->syms[0]);
}
}
static Symbol equated(Symbol p) {
{ Symbol q; for (q = p->u.l.equatedto; q; q = q->u.l.equatedto) assert(p != q); }
while (p->u.l.equatedto)
p = p->u.l.equatedto;
return p;
}
void emitcode(void) {
Code cp;
Coordinate save;
save = src;
cp = codehead.next;
for ( ; errcnt <= 0 && cp; cp = cp->next)
switch (cp->kind) {
case Address: break;
case Blockbeg: if (glevel && IR->stabblock) {
(*IR->stabblock)('{', cp->u.block.level - LOCAL, cp->u.block.locals);
swtoseg(CODE);
}
break;
case Blockend: if (glevel && IR->stabblock) {
Code bp = cp->u.begin;
foreach(bp->u.block.identifiers, bp->u.block.level, typestab, NULL);
foreach(bp->u.block.types, bp->u.block.level, typestab, NULL);
(*IR->stabblock)('}', bp->u.block.level - LOCAL, bp->u.block.locals);
swtoseg(CODE);
}
break;
case Defpoint: src = cp->u.point.src;
if (glevel > 0 && IR->stabline) {
(*IR->stabline)(&cp->u.point.src); swtoseg(CODE); } break;
case Gen: case Jump:
case Label: if (cp->u.forest)
(*IR->emit)(cp->u.forest); break;
case Local: if (glevel && IR->stabsym) {
(*IR->stabsym)(cp->u.var);
swtoseg(CODE);
} break;
case Switch: { int i;
defglobal(cp->u.swtch.table, LIT);
(*IR->defaddress)(equated(cp->u.swtch.labels[0]));
for (i = 1; i < cp->u.swtch.size; i++) {
long k = cp->u.swtch.values[i-1];
while (++k < cp->u.swtch.values[i])
assert(k < LONG_MAX),
(*IR->defaddress)(equated(cp->u.swtch.deflab));
(*IR->defaddress)(equated(cp->u.swtch.labels[i]));
}
swtoseg(CODE);
} break;
default: assert(0);
}
src = save;
}
static Node undag(Node forest) {
Node p;
tail = &forest;
for (p = forest; p; p = p->link)
if (generic(p->op) == INDIR) {
assert(p->count >= 1);
visit(p, 1);
if (p->syms[2]) {
assert(p->syms[2]->u.t.cse);
p->syms[2]->u.t.cse = NULL;
addlocal(p->syms[2]);
}
} else if (iscall(p->op) && p->count >= 1)
visit(p, 1);
else {
assert(p->count == 0),
visit(p, 1);
*tail = p;
tail = &p->link;
}
*tail = NULL;
return forest;
}
static Node replace(Node p) {
if (p && ( generic(p->op) == INDIR
&& generic(p->kids[0]->op) == ADDRL
&& p->kids[0]->syms[0]->temporary
&& p->kids[0]->syms[0]->u.t.replace)) {
p = p->kids[0]->syms[0]->u.t.cse;
if (generic(p->op) == INDIR && isaddrop(p->kids[0]->op))
p = newnode(p->op, newnode(p->kids[0]->op, NULL, NULL,
p->kids[0]->syms[0]), NULL, NULL);
else if (generic(p->op) == ADDRG)
p = newnode(p->op, NULL, NULL, p->syms[0]);
else
assert(0);
p->count = 1;
} else if (p) {
p->kids[0] = replace(p->kids[0]);
p->kids[1] = replace(p->kids[1]);
}
return p;
}
static Node prune(Node forest) {
Node p, *tail = &forest;
int count = 0;
for (p = forest; p; p = p->link) {
if (count > 0) {
p->kids[0] = replace(p->kids[0]);
p->kids[1] = replace(p->kids[1]);
}
if (( generic(p->op) == ASGN
&& generic(p->kids[0]->op) == ADDRL
&& p->kids[0]->syms[0]->temporary
&& p->kids[0]->syms[0]->u.t.cse == p->kids[1])) {
Symbol tmp = p->kids[0]->syms[0];
if (!tmp->defined)
(*IR->local)(tmp);
tmp->defined = 1;
if (( generic(p->kids[1]->op) == INDIR
&& isaddrop(p->kids[1]->kids[0]->op)
&& p->kids[1]->kids[0]->syms[0]->sclass == REGISTER)
|| (( generic(p->kids[1]->op) == INDIR
&& isaddrop(p->kids[1]->kids[0]->op)) && tmp->sclass == AUTO)
|| (generic(p->kids[1]->op) == ADDRG && tmp->sclass == AUTO)) {
tmp->u.t.replace = 1;
count++;
continue; /* and omit the assignment */
}
}
/* keep the assignment and other roots */
*tail = p;
tail = &(*tail)->link;
}
assert(*tail == NULL);
return forest;
}
static Node visit(Node p, int listed) {
if (p) {
if (p->syms[2])
p = tmpnode(p);
else if ((p->count <= 1 && !iscall(p->op))
|| (p->count == 0 && iscall(p->op))) {
p->kids[0] = visit(p->kids[0], 0);
p->kids[1] = visit(p->kids[1], 0);
}
else if (specific(p->op) == ADDRL+P || specific(p->op) == ADDRF+P) {
assert(!listed);
p = newnode(p->op, NULL, NULL, p->syms[0]);
p->count = 1;
}
else if (p->op == INDIR+B) {
p = newnode(p->op, p->kids[0], NULL, NULL);
p->count = 1;
p->kids[0] = visit(p->kids[0], 0);
p->kids[1] = visit(p->kids[1], 0);
}
else {
p->kids[0] = visit(p->kids[0], 0);
p->kids[1] = visit(p->kids[1], 0);
p->syms[2] = temporary(REGISTER, btot(p->op, opsize(p->op)));
assert(!p->syms[2]->defined);
p->syms[2]->ref = 1;
p->syms[2]->u.t.cse = p;
*tail = asgnnode(p->syms[2], p);
tail = &(*tail)->link;
if (!listed)
p = tmpnode(p);
};
}
return p;
}
static Node tmpnode(Node p) {
Symbol tmp = p->syms[2];
assert(tmp);
if (--p->count == 0)
p->syms[2] = NULL;
p = newnode(INDIR + ttob(tmp->type),
newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), NULL, NULL);
p->count = 1;
return p;
}
static Node asgnnode(Symbol tmp, Node p) {
p = newnode(ASGN + ttob(tmp->type),
newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), p, NULL);
p->syms[0] = intconst(tmp->type->size);
p->syms[1] = intconst(tmp->type->align);
return p;
}
/* printdag - print dag p on fd, or the node list if p == 0 */
void printdag(Node p, int fd) {
FILE *f = fd == 1 ? stdout : stderr;
printed(0);
if (p == 0) {
if ((p = forest) != NULL)
do {
p = p->link;
printdag1(p, fd, 0);
} while (p != forest);
} else if (*printed(nodeid((Tree)p)))
fprint(f, "node'%d printed above\n", nodeid((Tree)p));
else
printdag1(p, fd, 0);
}
/* printdag1 - recursively print dag p */
static void printdag1(Node p, int fd, int lev) {
int id, i;
if (p == 0 || *printed(id = nodeid((Tree)p)))
return;
*printed(id) = 1;
for (i = 0; i < NELEMS(p->kids); i++)
printdag1(p->kids[i], fd, lev + 1);
printnode(p, fd, lev);
}
/* printnode - print fields of dag p */
static void printnode(Node p, int fd, int lev) {
if (p) {
FILE *f = fd == 1 ? stdout : stderr;
int i, id = nodeid((Tree)p);
fprint(f, "%c%d%s", lev == 0 ? '\'' : '#', id,
&" "[id < 10 ? 0 : id < 100 ? 1 : 2]);
fprint(f, "%s count=%d", opname(p->op), p->count);
for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
fprint(f, " #%d", nodeid((Tree)p->kids[i]));
if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
fprint(f, " {%t}", p->syms[0]->type);
else
for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++)
if (p->syms[i]->name)
fprint(f, " %s", p->syms[i]->name);
else
fprint(f, " %p", p->syms[i]);
fprint(f, "\n");
}
}
/* typestab - emit stab entries for p */
static void typestab(Symbol p, void *cl) {
if (!isfunc(p->type) && (p->sclass == EXTERN || p->sclass == STATIC) && IR->stabsym)
(*IR->stabsym)(p);
else if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype)
(*IR->stabtype)(p);
}

View File

@@ -1,210 +0,0 @@
%{
#include "c.h"
typedef Node NODEPTR_TYPE;
#define OP_LABEL(p) (specific((p)->op))
#define LEFT_CHILD(p) ((p)->kids[0])
#define RIGHT_CHILD(p) ((p)->kids[1])
#define STATE_LABEL(p) ((p)->x.state)
#define PANIC error
%}
%term CNSTF=17 CNSTI=21 CNSTP=23 CNSTU=22
%term ARGB=41 ARGF=33 ARGI=37 ARGP=39 ARGU=38
%term ASGNB=57 ASGNF=49 ASGNI=53 ASGNP=55 ASGNU=54
%term INDIRB=73 INDIRF=65 INDIRI=69 INDIRP=71 INDIRU=70
%term CVFF=113 CVFI=117
%term CVIF=129 CVII=133 CVIU=134
%term CVPP=151 CVPU=150
%term CVUI=181 CVUP=183 CVUU=182
%term NEGF=193 NEGI=197
%term CALLB=217 CALLF=209 CALLI=213 CALLP=215 CALLU=214 CALLV=216
%term RETF=241 RETI=245 RETP=247 RETU=246 RETV=248
%term ADDRGP=263
%term ADDRFP=279
%term ADDRLP=295
%term ADDF=305 ADDI=309 ADDP=311 ADDU=310
%term SUBF=321 SUBI=325 SUBP=327 SUBU=326
%term LSHI=341 LSHU=342
%term MODI=357 MODU=358
%term RSHI=373 RSHU=374
%term BANDI=389 BANDU=390
%term BCOMI=405 BCOMU=406
%term BORI=421 BORU=422
%term BXORI=437 BXORU=438
%term DIVF=449 DIVI=453 DIVU=454
%term MULF=465 MULI=469 MULU=470
%term EQF=481 EQI=485 EQU=486
%term GEF=497 GEI=501 GEU=502
%term GTF=513 GTI=517 GTU=518
%term LEF=529 LEI=533 LEU=534
%term LTF=545 LTI=549 LTU=550
%term NEF=561 NEI=565 NEU=566
%term JUMPV=584
%term LABELV=600
%%
stmt: INDIRB(P) ""
stmt: INDIRF(P) ""
stmt: INDIRI(P) ""
stmt: INDIRU(P) ""
stmt: INDIRP(P) ""
stmt: CALLF(P) ""
stmt: CALLI(P) ""
stmt: CALLU(P) ""
stmt: CALLP(P) ""
stmt: V ""
bogus: I "" 1
bogus: U "" 1
bogus: P "" 1
bogus: F "" 1
bogus: B "" 1
bogus: V "" 1
I: bogus "" 1
U: bogus "" 1
P: bogus "" 1
F: bogus "" 1
B: bogus "" 1
V: bogus "" 1
F: CNSTF ""
I: CNSTI ""
P: CNSTP ""
U: CNSTU ""
V: ARGB(B) ""
V: ARGF(F) ""
V: ARGI(I) ""
V: ARGU(U) ""
V: ARGP(P) ""
V: ASGNB(P,B) ""
V: ASGNF(P,F) ""
V: ASGNI(P,I) ""
V: ASGNU(P,U) ""
V: ASGNP(P,P) ""
B: INDIRB(P) ""
F: INDIRF(P) ""
I: INDIRI(P) ""
U: INDIRU(P) ""
P: INDIRP(P) ""
I: CVII(I) ""
I: CVUI(U) ""
I: CVFI(F) ""
U: CVIU(I) ""
U: CVUU(U) ""
U: CVPU(P) ""
F: CVIF(I) ""
F: CVFF(F) ""
P: CVUP(U) ""
P: CVPP(P) ""
F: NEGF(F) ""
I: NEGI(I) ""
V: CALLB(P,P) ""
F: CALLF(P) ""
I: CALLI(P) ""
U: CALLU(P) ""
P: CALLP(P) ""
V: CALLV(P) ""
V: RETF(F) ""
V: RETI(I) ""
V: RETU(U) ""
V: RETP(P) ""
V: RETV ""
P: ADDRGP ""
P: ADDRFP ""
P: ADDRLP ""
F: ADDF(F,F) ""
I: ADDI(I,I) ""
P: ADDP(P,I) ""
P: ADDP(I,P) ""
P: ADDP(U,P) ""
P: ADDP(P,U) ""
U: ADDU(U,U) ""
F: SUBF(F,F) ""
I: SUBI(I,I) ""
P: SUBP(P,I) ""
P: SUBP(P,U) ""
U: SUBU(U,U) ""
I: LSHI(I,I) ""
U: LSHU(U,I) ""
I: MODI(I,I) ""
U: MODU(U,U) ""
I: RSHI(I,I) ""
U: RSHU(U,I) ""
U: BANDU(U,U) ""
I: BANDI(I,I) ""
U: BCOMU(U) ""
I: BCOMI(I) ""
I: BORI(I,I) ""
U: BORU(U,U) ""
U: BXORU(U,U) ""
I: BXORI(I,I) ""
F: DIVF(F,F) ""
I: DIVI(I,I) ""
U: DIVU(U,U) ""
F: MULF(F,F) ""
I: MULI(I,I) ""
U: MULU(U,U) ""
V: EQF(F,F) ""
V: EQI(I,I) ""
V: EQU(U,U) ""
V: GEF(F,F) ""
V: GEI(I,I) ""
V: GEU(U,U) ""
V: GTF(F,F) ""
V: GTI(I,I) ""
V: GTU(U,U) ""
V: LEF(F,F) ""
V: LEI(I,I) ""
V: LEU(U,U) ""
V: LTF(F,F) ""
V: LTI(I,I) ""
V: LTU(U,U) ""
V: NEF(F,F) ""
V: NEI(I,I) ""
V: NEU(U,U) ""
V: JUMPV(P) ""
V: LABELV ""
%%
static void reduce(NODEPTR_TYPE p, int goalnt) {
int i, sz = opsize(p->op), rulenumber = _rule(p->x.state, goalnt);
short *nts = _nts[rulenumber];
NODEPTR_TYPE kids[10];
assert(rulenumber);
_kids(p, rulenumber, kids);
for (i = 0; nts[i]; i++)
reduce(kids[i], nts[i]);
switch (optype(p->op)) {
#define xx(ty) if (sz == ty->size) return
case I:
case U:
xx(chartype);
xx(shorttype);
xx(inttype);
xx(longtype);
xx(longlong);
break;
case F:
xx(floattype);
xx(doubletype);
xx(longdouble);
break;
case P:
xx(voidptype);
xx(funcptype);
break;
case V:
case B: if (sz == 0) return;
#undef xx
}
printdag(p, 2);
assert(0);
}
void check(Node p) {
struct _state { short cost[1]; };
_label(p);
if (((struct _state *)p->x.state)->cost[1] > 0) {
printdag(p, 2);
assert(0);
}
reduce(p, 1);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,545 +0,0 @@
#include "c.h"
static Tree addtree(int, Tree, Tree);
static Tree andtree(int, Tree, Tree);
static Tree cmptree(int, Tree, Tree);
static int compatible(Type, Type);
static int isnullptr(Tree e);
static Tree multree(int, Tree, Tree);
static Tree subtree(int, Tree, Tree);
#define isvoidptr(ty) \
(isptr(ty) && unqual(ty->type) == voidtype)
Tree (*optree[])(int, Tree, Tree) = {
#define xx(a,b,c,d,e,f,g) e,
#define yy(a,b,c,d,e,f,g) e,
#include "token.h"
};
Tree call(Tree f, Type fty, Coordinate src) {
int n = 0;
Tree args = NULL, r = NULL, e;
Type *proto, rty = unqual(freturn(fty));
Symbol t3 = NULL;
if (fty->u.f.oldstyle)
proto = NULL;
else
proto = fty->u.f.proto;
if (hascall(f))
r = f;
if (isstruct(rty))
{
t3 = temporary(AUTO, unqual(rty));
if (rty->size == 0)
error("illegal use of incomplete type `%t'\n", rty);
}
if (t != ')')
for (;;) {
Tree q = pointer(expr1(0));
if (proto && *proto && *proto != voidtype)
{
Type aty;
q = value(q);
aty = assign(*proto, q);
if (aty)
q = cast(q, aty);
else
error("type error in argument %d to %s; found `%t' expected `%t'\n", n + 1, funcname(f),
q->type, *proto);
if ((isint(q->type) || isenum(q->type))
&& q->type->size != inttype->size)
q = cast(q, promote(q->type));
++proto;
}
else
{
if (!fty->u.f.oldstyle && *proto == NULL)
error("too many arguments to %s\n", funcname(f));
q = value(q);
if (isarray(q->type) || q->type->size == 0)
error("type error in argument %d to %s; `%t' is illegal\n", n + 1, funcname(f), q->type);
else
q = cast(q, promote(q->type));
}
if (!IR->wants_argb && isstruct(q->type)) {
if (iscallb(q))
q = addrof(q);
else {
Symbol t1 = temporary(AUTO, unqual(q->type));
q = asgn(t1, q);
q = tree(RIGHT, ptr(t1->type),
root(q), lvalue(idtree(t1)));
}
}
if (q->type->size == 0)
q->type = inttype;
if (hascall(q))
r = r ? tree(RIGHT, voidtype, r, q) : q;
args = tree(mkop(ARG, q->type), q->type, q, args);
n++;
if (Aflag >= 2 && n == 32)
warning("more than 31 arguments in a call to %s\n",
funcname(f));
if (t != ',')
break;
t = gettok();
}
expect(')');
if (proto && *proto && *proto != voidtype)
error("insufficient number of arguments to %s\n",
funcname(f));
if (r)
args = tree(RIGHT, voidtype, r, args);
e = calltree(f, rty, args, t3);
if (events.calls)
apply(events.calls, &src, &e);
return e;
}
Tree calltree(Tree f, Type ty, Tree args, Symbol t3) {
Tree p;
if (args)
f = tree(RIGHT, f->type, args, f);
if (isstruct(ty))
assert(t3),
p = tree(RIGHT, ty,
tree(CALL+B, ty, f, addrof(idtree(t3))),
idtree(t3));
else {
Type rty = ty;
if (isenum(ty))
rty = unqual(ty)->type;
if (!isfloat(rty))
rty = promote(rty);
p = tree(mkop(CALL, rty), rty, f, NULL);
if (isptr(ty) || p->type->size > ty->size)
p = cast(p, ty);
}
return p;
}
Tree vcall(Symbol func, Type ty, ...) {
va_list ap;
Tree args = NULL, e, f = pointer(idtree(func)), r = NULL;
assert(isfunc(func->type));
if (ty == NULL)
ty = freturn(func->type);
va_start(ap, ty);
while ((e = va_arg(ap, Tree)) != NULL) {
if (hascall(e))
r = r == NULL ? e : tree(RIGHT, voidtype, r, e);
args = tree(mkop(ARG, e->type), e->type, e, args);
}
va_end(ap);
if (r != NULL)
args = tree(RIGHT, voidtype, r, args);
return calltree(f, ty, args, NULL);
}
int iscallb(Tree e) {
return e->op == RIGHT && e->kids[0] && e->kids[1]
&& e->kids[0]->op == CALL+B
&& e->kids[1]->op == INDIR+B
&& isaddrop(e->kids[1]->kids[0]->op)
&& e->kids[1]->kids[0]->u.sym->temporary;
}
static Tree addtree(int op, Tree l, Tree r) {
Type ty = inttype;
if (isarith(l->type) && isarith(r->type)) {
ty = binary(l->type, r->type);
l = cast(l, ty);
r = cast(r, ty);
} else if (isptr(l->type) && isint(r->type))
return addtree(ADD, r, l);
else if ( isptr(r->type) && isint(l->type)
&& !isfunc(r->type->type))
{
long n;
ty = unqual(r->type);
n = unqual(ty->type)->size;
if (n == 0)
error("unknown size for type `%t'\n", ty->type);
l = cast(l, promote(l->type));
if (n > 1)
l = multree(MUL, cnsttree(signedptr, n), l);
if (YYcheck && !isaddrop(r->op)) /* omit */
return nullcall(ty, YYcheck, r, l); /* omit */
return simplify(ADD, ty, l, r);
}
else
typeerror(op, l, r);
return simplify(op, ty, l, r);
}
Tree cnsttree(Type ty, ...) {
Tree p = tree(mkop(CNST,ty), ty, NULL, NULL);
va_list ap;
va_start(ap, ty);
switch (ty->op) {
case INT: p->u.v.i = va_arg(ap, long); break;
case UNSIGNED:p->u.v.u = va_arg(ap, unsigned long)&ones(8*ty->size); break;
case FLOAT: p->u.v.d = va_arg(ap, double); break;
case POINTER: p->u.v.p = va_arg(ap, void *); break;
default: assert(0);
}
va_end(ap);
return p;
}
Tree consttree(unsigned n, Type ty) {
if (isarray(ty))
ty = atop(ty);
else assert(isint(ty));
return cnsttree(ty, (unsigned long)n);
}
static Tree cmptree(int op, Tree l, Tree r) {
Type ty;
if (isarith(l->type) && isarith(r->type)) {
ty = binary(l->type, r->type);
l = cast(l, ty);
r = cast(r, ty);
} else if (compatible(l->type, r->type)) {
ty = unsignedptr;
l = cast(l, ty);
r = cast(r, ty);
} else {
ty = unsignedtype;
typeerror(op, l, r);
}
return simplify(mkop(op,ty), inttype, l, r);
}
static int compatible(Type ty1, Type ty2) {
return isptr(ty1) && !isfunc(ty1->type)
&& isptr(ty2) && !isfunc(ty2->type)
&& eqtype(unqual(ty1->type), unqual(ty2->type), 0);
}
static int isnullptr(Tree e) {
Type ty = unqual(e->type);
return generic(e->op) == CNST
&& ((ty->op == INT && e->u.v.i == 0)
|| (ty->op == UNSIGNED && e->u.v.u == 0)
|| (isvoidptr(ty) && e->u.v.p == NULL));
}
Tree eqtree(int op, Tree l, Tree r) {
Type xty = l->type, yty = r->type;
if ((isptr(xty) && isnullptr(r))
|| (isptr(xty) && !isfunc(xty->type) && isvoidptr(yty))
|| (isptr(xty) && isptr(yty)
&& eqtype(unqual(xty->type), unqual(yty->type), 1))) {
Type ty = unsignedptr;
l = cast(l, ty);
r = cast(r, ty);
return simplify(mkop(op,ty), inttype, l, r);
}
if ((isptr(yty) && isnullptr(l))
|| (isptr(yty) && !isfunc(yty->type) && isvoidptr(xty)))
return eqtree(op, r, l);
return cmptree(op, l, r);
}
Type assign(Type xty, Tree e) {
Type yty = unqual(e->type);
xty = unqual(xty);
if (isenum(xty))
xty = xty->type;
if (xty->size == 0 || yty->size == 0)
return NULL;
if ( (isarith(xty) && isarith(yty))
|| (isstruct(xty) && xty == yty))
return xty;
if (isptr(xty) && isnullptr(e))
return xty;
if (((isvoidptr(xty) && isptr(yty))
|| (isptr(xty) && isvoidptr(yty)))
&& ( (isconst(xty->type) || !isconst(yty->type))
&& (isvolatile(xty->type) || !isvolatile(yty->type))))
return xty;
if ((isptr(xty) && isptr(yty)
&& eqtype(unqual(xty->type), unqual(yty->type), 1))
&& ( (isconst(xty->type) || !isconst(yty->type))
&& (isvolatile(xty->type) || !isvolatile(yty->type))))
return xty;
if (isptr(xty) && isptr(yty)
&& ( (isconst(xty->type) || !isconst(yty->type))
&& (isvolatile(xty->type) || !isvolatile(yty->type)))) {
Type lty = unqual(xty->type), rty = unqual(yty->type);
if ((isenum(lty) && rty == inttype)
|| (isenum(rty) && lty == inttype)) {
if (Aflag >= 1)
warning("assignment between `%t' and `%t' is compiler-dependent\n",
xty, yty);
return xty;
}
}
return NULL;
}
Tree asgntree(int op, Tree l, Tree r) {
Type aty, ty;
r = pointer(r);
ty = assign(l->type, r);
if (ty)
r = cast(r, ty);
else {
typeerror(ASGN, l, r);
if (r->type == voidtype)
r = retype(r, inttype);
ty = r->type;
}
if (l->op != FIELD)
l = lvalue(l);
aty = l->type;
if (isptr(aty))
aty = unqual(aty)->type;
if ( isconst(aty)
|| (isstruct(aty) && unqual(aty)->u.sym->u.s.cfields)) {
if (isaddrop(l->op)
&& !l->u.sym->computed && !l->u.sym->generated)
error("assignment to const identifier `%s'\n",
l->u.sym->name);
else
error("assignment to const location\n");
}
if (l->op == FIELD) {
long n = 8*l->u.field->type->size - fieldsize(l->u.field);
if (n > 0 && isunsigned(l->u.field->type))
r = bittree(BAND, r,
cnsttree(r->type, (unsigned long)fieldmask(l->u.field)));
else if (n > 0) {
if (r->op == CNST+I) {
n = r->u.v.i;
if (n&(1<<(fieldsize(l->u.field)-1)))
n |= ~0UL<<fieldsize(l->u.field);
r = cnsttree(r->type, n);
} else
r = shtree(RSH,
shtree(LSH, r, cnsttree(inttype, n)),
cnsttree(inttype, n));
}
}
if (isstruct(ty) && isaddrop(l->op) && iscallb(r))
return tree(RIGHT, ty,
tree(CALL+B, ty, r->kids[0]->kids[0], l),
idtree(l->u.sym));
return tree(mkop(op,ty), ty, l, r);
}
Tree condtree(Tree e, Tree l, Tree r) {
Symbol t1;
Type ty, xty = l->type, yty = r->type;
Tree p;
if (isarith(xty) && isarith(yty))
ty = binary(xty, yty);
else if (eqtype(xty, yty, 1))
ty = unqual(xty);
else if (isptr(xty) && isnullptr(r))
ty = xty;
else if (isnullptr(l) && isptr(yty))
ty = yty;
else if ((isptr(xty) && !isfunc(xty->type) && isvoidptr(yty))
|| (isptr(yty) && !isfunc(yty->type) && isvoidptr(xty)))
ty = voidptype;
else if ((isptr(xty) && isptr(yty)
&& eqtype(unqual(xty->type), unqual(yty->type), 1)))
ty = xty;
else {
typeerror(COND, l, r);
return consttree(0, inttype);
}
if (isptr(ty)) {
ty = unqual(unqual(ty)->type);
if ((isptr(xty) && isconst(unqual(xty)->type))
|| (isptr(yty) && isconst(unqual(yty)->type)))
ty = qual(CONST, ty);
if ((isptr(xty) && isvolatile(unqual(xty)->type))
|| (isptr(yty) && isvolatile(unqual(yty)->type)))
ty = qual(VOLATILE, ty);
ty = ptr(ty);
}
switch (e->op) {
case CNST+I: return cast(e->u.v.i != 0 ? l : r, ty);
case CNST+U: return cast(e->u.v.u != 0 ? l : r, ty);
case CNST+P: return cast(e->u.v.p != 0 ? l : r, ty);
case CNST+F: return cast(e->u.v.d != 0.0 ? l : r, ty);
}
if (ty != voidtype && ty->size > 0) {
t1 = genident(REGISTER, unqual(ty), level);
/* t1 = temporary(REGISTER, unqual(ty)); */
l = asgn(t1, l);
r = asgn(t1, r);
} else
t1 = NULL;
p = tree(COND, ty, cond(e),
tree(RIGHT, ty, root(l), root(r)));
p->u.sym = t1;
return p;
}
/* addrof - address of p */
Tree addrof(Tree p) {
Tree q = p;
for (;;)
switch (generic(q->op)) {
case RIGHT:
assert(q->kids[0] || q->kids[1]);
q = q->kids[1] ? q->kids[1] : q->kids[0];
continue;
case ASGN:
q = q->kids[1];
continue;
case COND: {
Symbol t1 = q->u.sym;
q->u.sym = 0;
q = idtree(t1);
/* fall thru */
}
case INDIR:
if (p == q)
return q->kids[0];
q = q->kids[0];
return tree(RIGHT, q->type, root(p), q);
default:
error("addressable object required\n");
return value(p);
}
}
/* andtree - construct tree for l [&& ||] r */
static Tree andtree(int op, Tree l, Tree r) {
if (!isscalar(l->type) || !isscalar(r->type))
typeerror(op, l, r);
return simplify(op, inttype, cond(l), cond(r));
}
/* asgn - generate tree for assignment of expr e to symbol p sans qualifiers */
Tree asgn(Symbol p, Tree e) {
if (isarray(p->type))
e = tree(ASGN+B, p->type, idtree(p),
tree(INDIR+B, e->type, e, NULL));
else {
Type ty = p->type;
p->type = unqual(p->type);
if (isstruct(p->type) && p->type->u.sym->u.s.cfields) {
p->type->u.sym->u.s.cfields = 0;
e = asgntree(ASGN, idtree(p), e);
p->type->u.sym->u.s.cfields = 1;
} else
e = asgntree(ASGN, idtree(p), e);
p->type = ty;
}
return e;
}
/* bittree - construct tree for l [& | ^ %] r */
Tree bittree(int op, Tree l, Tree r) {
Type ty = inttype;
if (isint(l->type) && isint(r->type)) {
ty = binary(l->type, r->type);
l = cast(l, ty);
r = cast(r, ty);
} else
typeerror(op, l, r);
return simplify(op, ty, l, r);
}
/* multree - construct tree for l [* /] r */
static Tree multree(int op, Tree l, Tree r) {
Type ty = inttype;
if (isarith(l->type) && isarith(r->type)) {
ty = binary(l->type, r->type);
l = cast(l, ty);
r = cast(r, ty);
} else
typeerror(op, l, r);
return simplify(op, ty, l, r);
}
/* shtree - construct tree for l [>> <<] r */
Tree shtree(int op, Tree l, Tree r) {
Type ty = inttype;
if (isint(l->type) && isint(r->type)) {
ty = promote(l->type);
l = cast(l, ty);
r = cast(r, inttype);
} else
typeerror(op, l, r);
return simplify(op, ty, l, r);
}
/* subtree - construct tree for l - r */
static Tree subtree(int op, Tree l, Tree r) {
long n;
Type ty = inttype;
if (isarith(l->type) && isarith(r->type)) {
ty = binary(l->type, r->type);
l = cast(l, ty);
r = cast(r, ty);
} else if (isptr(l->type) && !isfunc(l->type->type) && isint(r->type)) {
ty = unqual(l->type);
n = unqual(ty->type)->size;
if (n == 0)
error("unknown size for type `%t'\n", ty->type);
r = cast(r, promote(r->type));
if (n > 1)
r = multree(MUL, cnsttree(signedptr, n), r);
if (isunsigned(r->type))
r = cast(r, unsignedptr);
else
r = cast(r, signedptr);
return simplify(SUB+P, ty, l, r);
} else if (compatible(l->type, r->type)) {
ty = unqual(l->type);
n = unqual(ty->type)->size;
if (n == 0)
error("unknown size for type `%t'\n", ty->type);
l = simplify(SUB+U, unsignedptr,
cast(l, unsignedptr), cast(r, unsignedptr));
return simplify(DIV+I, longtype,
cast(l, longtype), cnsttree(longtype, n));
} else
typeerror(op, l, r);
return simplify(op, ty, l, r);
}
/* typeerror - issue "operands of op have illegal types `l' and `r'" */
void typeerror(int op, Tree l, Tree r) {
int i;
static struct { int op; char *name; } ops[] = {
{ASGN, "="}, {INDIR, "*"}, {NEG, "-"},
{ADD, "+"}, {SUB, "-"}, {LSH, "<<"},
{MOD, "%"}, {RSH, ">>"}, {BAND, "&"},
{BCOM, "~"}, {BOR, "|"}, {BXOR, "^"},
{DIV, "/"}, {MUL, "*"}, {EQ, "=="},
{GE, ">="}, {GT, ">"}, {LE, "<="},
{LT, "<"}, {NE, "!="}, {AND, "&&"},
{NOT, "!"}, {OR, "||"}, {COND, "?:"},
{0, 0}
};
op = generic(op);
for (i = 0; ops[i].op; i++)
if (op == ops[i].op)
break;
assert(ops[i].name);
if (r)
error("operands of %s have illegal types `%t' and `%t'\n",
ops[i].name, l->type, r->type);
else
error("operand of unary %s has illegal type `%t'\n", ops[i].name,
l->type);
}

View File

@@ -1,137 +0,0 @@
#include "c.h"
static void printtoken(void);
int errcnt = 0;
int errlimit = 20;
char kind[] = {
#define xx(a,b,c,d,e,f,g) f,
#define yy(a,b,c,d,e,f,g) f,
#include "token.h"
};
int wflag; /* != 0 to suppress warning messages */
void test(int tok, char set[]) {
if (t == tok)
t = gettok();
else {
expect(tok);
skipto(tok, set);
if (t == tok)
t = gettok();
}
}
void expect(int tok) {
if (t == tok)
t = gettok();
else {
error("syntax error; found");
printtoken();
fprint(stderr, " expecting `%k'\n", tok);
}
}
void error(const char *fmt, ...) {
va_list ap;
if (errcnt++ >= errlimit) {
errcnt = -1;
error("too many errors\n");
exit(1);
}
va_start(ap, fmt);
if (firstfile != file && firstfile && *firstfile)
fprint(stderr, "%s: ", firstfile);
fprint(stderr, "%w: ", &src);
vfprint(stderr, NULL, fmt, ap);
va_end(ap);
}
void skipto(int tok, char set[]) {
int n;
char *s;
assert(set);
for (n = 0; t != EOI && t != tok; t = gettok()) {
for (s = set; *s && kind[t] != *s; s++)
;
if (kind[t] == *s)
break;
if (n++ == 0)
error("skipping");
if (n <= 8)
printtoken();
else if (n == 9)
fprint(stderr, " ...");
}
if (n > 8) {
fprint(stderr, " up to");
printtoken();
}
if (n > 0)
fprint(stderr, "\n");
}
/* fatal - issue fatal error message and exit */
int fatal(const char *name, const char *fmt, int n) {
print("\n");
errcnt = -1;
error("compiler error in %s--", name);
fprint(stderr, fmt, n);
exit(EXIT_FAILURE);
return 0;
}
/* printtoken - print current token preceeded by a space */
static void printtoken(void) {
switch (t) {
case ID: fprint(stderr, " `%s'", token); break;
case ICON:
fprint(stderr, " `%s'", vtoa(tsym->type, tsym->u.c.v));
break;
case SCON: {
int i, n;
if (ischar(tsym->type->type)) {
char *s = tsym->u.c.v.p;
n = tsym->type->size;
fprint(stderr, " \"");
for (i = 0; i < 20 && i < n && *s; s++, i++)
if (*s < ' ' || *s >= 0177)
fprint(stderr, "\\%o", *s);
else
fprint(stderr, "%c", *s);
} else { /* wchar_t string */
unsigned int *s = tsym->u.c.v.p;
assert(tsym->type->type->size == widechar->size);
n = tsym->type->size/widechar->size;
fprint(stderr, " L\"");
for (i = 0; i < 20 && i < n && *s; s++, i++)
if (*s < ' ' || *s >= 0177)
fprint(stderr, "\\x%x", *s);
else
fprint(stderr, "%c", *s);
}
if (i < n)
fprint(stderr, " ...");
else
fprint(stderr, "\"");
break;
}
case FCON:
fprint(stderr, " `%S'", token, (char*)cp - token);
break;
case '`': case '\'': fprint(stderr, " \"%k\"", t); break;
default: fprint(stderr, " `%k'", t);
}
}
/* warning - issue warning error message */
void warning(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
if (wflag == 0) {
errcnt--;
error("warning: ");
vfprint(stderr, NULL, fmt, ap);
}
va_end(ap);
}

View File

@@ -1,28 +0,0 @@
#include "c.h"
struct entry {
Apply func;
void *cl;
};
Events events;
void attach(Apply func, void *cl, List *list) {
struct entry *p;
NEW(p, PERM);
p->func = func;
p->cl = cl;
*list = append(p, *list);
}
void apply(List event, void *arg1, void *arg2) {
if (event) {
List lp = event;
do {
struct entry *p = lp->x;
(*p->func)(p->cl, arg1, arg2);
lp = lp->link;
} while (lp != event);
}
}

View File

@@ -1,711 +0,0 @@
#include "c.h"
static char prec[] = {
#define xx(a,b,c,d,e,f,g) c,
#define yy(a,b,c,d,e,f,g) c,
#include "token.h"
};
static int oper[] = {
#define xx(a,b,c,d,e,f,g) d,
#define yy(a,b,c,d,e,f,g) d,
#include "token.h"
};
float refinc = 1.0;
static Tree expr2(void);
static Tree expr3(int);
static Tree nullcheck(Tree);
static Tree postfix(Tree);
static Tree unary(void);
static Tree primary(void);
static Type super(Type ty);
static Type super(Type ty) {
switch (ty->op) {
case INT:
if (ty->size < inttype->size)
return inttype;
break;
case UNSIGNED:
if (ty->size < unsignedtype->size)
return unsignedtype;
break;
case POINTER:
return unsignedptr;
}
return ty;
}
Tree expr(int tok) {
static char stop[] = { IF, ID, '}', 0 };
Tree p = expr1(0);
while (t == ',') {
Tree q;
t = gettok();
q = pointer(expr1(0));
p = tree(RIGHT, q->type, root(value(p)), q);
}
if (tok)
test(tok, stop);
return p;
}
Tree expr0(int tok) {
return root(expr(tok));
}
Tree expr1(int tok) {
static char stop[] = { IF, ID, 0 };
Tree p = expr2();
if (t == '='
|| (prec[t] >= 6 && prec[t] <= 8)
|| (prec[t] >= 11 && prec[t] <= 13)) {
int op = t;
t = gettok();
if (oper[op] == ASGN)
p = asgntree(ASGN, p, value(expr1(0)));
else
{
expect('=');
p = incr(op, p, expr1(0));
}
}
if (tok)
test(tok, stop);
return p;
}
Tree incr(int op, Tree v, Tree e) {
return asgntree(ASGN, v, (*optree[op])(oper[op], v, e));
}
static Tree expr2(void) {
Tree p = expr3(4);
if (t == '?') {
Tree l, r;
Coordinate pts[2];
if (Aflag > 1 && isfunc(p->type))
warning("%s used in a conditional expression\n",
funcname(p));
p = pointer(p);
t = gettok();
pts[0] = src;
l = pointer(expr(':'));
pts[1] = src;
r = pointer(expr2());
if (events.points)
{
apply(events.points, &pts[0], &l);
apply(events.points, &pts[1], &r);
}
p = condtree(p, l, r);
}
return p;
}
Tree value(Tree p) {
int op = generic(rightkid(p)->op);
if (p->type != voidtype
&& (op==AND || op==OR || op==NOT || op==EQ || op==NE
|| op== LE || op==LT || op== GE || op==GT))
p = condtree(p, consttree(1, inttype),
consttree(0, inttype));
return p;
}
static Tree expr3(int k) {
int k1;
Tree p = unary();
for (k1 = prec[t]; k1 >= k; k1--)
while (prec[t] == k1 && *cp != '=') {
Tree r;
Coordinate pt;
int op = t;
t = gettok();
pt = src;
p = pointer(p);
if (op == ANDAND || op == OROR) {
r = pointer(expr3(k1));
if (events.points)
apply(events.points, &pt, &r);
} else
r = pointer(expr3(k1 + 1));
p = (*optree[op])(oper[op], p, r);
}
return p;
}
static Tree unary(void) {
Tree p;
switch (t) {
case '*': t = gettok(); p = unary(); p = pointer(p);
if (isptr(p->type)
&& (isfunc(p->type->type) || isarray(p->type->type)))
p = retype(p, p->type->type);
else {
if (YYnull)
p = nullcheck(p);
p = rvalue(p);
} break;
case '&': t = gettok(); p = unary(); if (isarray(p->type) || isfunc(p->type))
p = retype(p, ptr(p->type));
else
p = lvalue(p);
if (isaddrop(p->op) && p->u.sym->sclass == REGISTER)
error("invalid operand of unary &; `%s' is declared register\n", p->u.sym->name);
else if (isaddrop(p->op))
p->u.sym->addressed = 1;
break;
case '+': t = gettok(); p = unary(); p = pointer(p);
if (isarith(p->type))
p = cast(p, promote(p->type));
else
typeerror(ADD, p, NULL); break;
case '-': t = gettok(); p = unary(); p = pointer(p);
if (isarith(p->type)) {
Type ty = promote(p->type);
p = cast(p, ty);
if (isunsigned(ty)) {
warning("unsigned operand of unary -\n");
p = simplify(ADD, ty, simplify(BCOM, ty, p, NULL), cnsttree(ty, 1UL));
} else
p = simplify(NEG, ty, p, NULL);
} else
typeerror(SUB, p, NULL); break;
case '~': t = gettok(); p = unary(); p = pointer(p);
if (isint(p->type)) {
Type ty = promote(p->type);
p = simplify(BCOM, ty, cast(p, ty), NULL);
} else
typeerror(BCOM, p, NULL); break;
case '!': t = gettok(); p = unary(); p = pointer(p);
if (isscalar(p->type))
p = simplify(NOT, inttype, cond(p), NULL);
else
typeerror(NOT, p, NULL); break;
case INCR: t = gettok(); p = unary(); p = incr(INCR, pointer(p), consttree(1, inttype)); break;
case DECR: t = gettok(); p = unary(); p = incr(DECR, pointer(p), consttree(1, inttype)); break;
case TYPECODE: case SIZEOF: { int op = t;
Type ty;
p = NULL;
t = gettok();
if (t == '(') {
t = gettok();
if (istypename(t, tsym)) {
ty = typename();
expect(')');
} else {
p = postfix(expr(')'));
ty = p->type;
}
} else {
p = unary();
ty = p->type;
}
assert(ty);
if (op == TYPECODE)
p = cnsttree(inttype, (long)ty->op);
else {
if (isfunc(ty) || ty->size == 0)
error("invalid type argument `%t' to `sizeof'\n", ty);
else if (p && rightkid(p)->op == FIELD)
error("`sizeof' applied to a bit field\n");
p = cnsttree(unsignedlong, (unsigned long)ty->size);
} } break;
case '(':
t = gettok();
if (istypename(t, tsym)) {
Type ty, ty1 = typename(), pty;
expect(')');
ty = unqual(ty1);
if (isenum(ty)) {
Type ty2 = ty->type;
if (isconst(ty1))
ty2 = qual(CONST, ty2);
if (isvolatile(ty1))
ty2 = qual(VOLATILE, ty2);
ty1 = ty2;
ty = ty->type;
}
p = pointer(unary());
pty = p->type;
if (isenum(pty))
pty = pty->type;
if ((isarith(pty) && isarith(ty))
|| (isptr(pty) && isptr(ty))) {
explicitCast++;
p = cast(p, ty);
explicitCast--;
} else if ((isptr(pty) && isint(ty))
|| (isint(pty) && isptr(ty))) {
if (Aflag >= 1 && ty->size < pty->size)
warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, ty);
p = cast(p, ty);
} else if (ty != voidtype) {
error("cast from `%t' to `%t' is illegal\n",
p->type, ty1);
ty1 = inttype;
}
if (generic(p->op) == INDIR || ty->size == 0)
p = tree(RIGHT, ty1, NULL, p);
else
p = retype(p, ty1);
} else
p = postfix(expr(')'));
break;
default:
p = postfix(primary());
}
return p;
}
static Tree postfix(Tree p) {
for (;;)
switch (t) {
case INCR: p = tree(RIGHT, p->type,
tree(RIGHT, p->type,
p,
incr(t, p, consttree(1, inttype))),
p);
t = gettok(); break;
case DECR: p = tree(RIGHT, p->type,
tree(RIGHT, p->type,
p,
incr(t, p, consttree(1, inttype))),
p);
t = gettok(); break;
case '[': {
Tree q;
t = gettok();
q = expr(']');
if (YYnull) {
if (isptr(p->type))
p = nullcheck(p);
else if (isptr(q->type))
q = nullcheck(q);
}
p = (*optree['+'])(ADD, pointer(p), pointer(q));
if (isptr(p->type) && isarray(p->type->type))
p = retype(p, p->type->type);
else
p = rvalue(p);
} break;
case '(': {
Type ty;
Coordinate pt;
p = pointer(p);
if (isptr(p->type) && isfunc(p->type->type))
ty = p->type->type;
else {
error("found `%t' expected a function\n", p->type);
ty = func(voidtype, NULL, 1);
p = retype(p, ptr(ty));
}
pt = src;
t = gettok();
p = call(p, ty, pt);
} break;
case '.': t = gettok();
if (t == ID) {
if (isstruct(p->type)) {
Tree q = addrof(p);
p = field(q, token);
q = rightkid(q);
if (isaddrop(q->op) && q->u.sym->temporary)
p = tree(RIGHT, p->type, p, NULL);
} else
error("left operand of . has incompatible type `%t'\n",
p->type);
t = gettok();
} else
error("field name expected\n"); break;
case DEREF: t = gettok();
p = pointer(p);
if (t == ID) {
if (isptr(p->type) && isstruct(p->type->type)) {
if (YYnull)
p = nullcheck(p);
p = field(p, token);
} else
error("left operand of -> has incompatible type `%t'\n", p->type);
t = gettok();
} else
error("field name expected\n"); break;
default:
return p;
}
}
static Tree primary(void) {
Tree p;
assert(t != '(');
switch (t) {
case ICON:
case FCON: p = tree(mkop(CNST,tsym->type), tsym->type, NULL, NULL);
p->u.v = tsym->u.c.v;
break;
case SCON: if (ischar(tsym->type->type))
tsym->u.c.v.p = stringn(tsym->u.c.v.p, tsym->type->size);
else
tsym->u.c.v.p = memcpy(allocate(tsym->type->size, PERM), tsym->u.c.v.p, tsym->type->size);
tsym = constant(tsym->type, tsym->u.c.v);
if (tsym->u.c.loc == NULL)
tsym->u.c.loc = genident(STATIC, tsym->type, GLOBAL);
p = idtree(tsym->u.c.loc); break;
case ID: if (tsym == NULL)
{
Symbol p = install(token, &identifiers, level, FUNC);
p->src = src;
if (getchr() == '(') {
Symbol q = lookup(token, externals);
p->type = func(inttype, NULL, 1);
p->sclass = EXTERN;
if (Aflag >= 1)
warning("missing prototype\n");
if (q && !eqtype(q->type, p->type, 1))
warning("implicit declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src);
if (q == NULL) {
q = install(p->name, &externals, GLOBAL, PERM);
q->type = p->type;
q->sclass = EXTERN;
q->src = src;
(*IR->defsymbol)(q);
}
p->u.alias = q;
} else {
error("undeclared identifier `%s'\n", p->name);
p->sclass = AUTO;
p->type = inttype;
if (p->scope == GLOBAL)
(*IR->defsymbol)(p);
else
addlocal(p);
}
t = gettok();
if (xref)
use(p, src);
return idtree(p);
}
if (xref)
use(tsym, src);
if (tsym->sclass == ENUM)
p = consttree(tsym->u.value, inttype);
else {
if (tsym->sclass == TYPEDEF)
error("illegal use of type name `%s'\n", tsym->name);
p = idtree(tsym);
} break;
case FIRSTARG:
if (level > PARAM && cfunc && cfunc->u.f.callee[0])
p = idtree(cfunc->u.f.callee[0]);
else {
error("illegal use of `%k'\n", FIRSTARG);
p = cnsttree(inttype, 0L);
}
break;
default:
error("illegal expression\n");
p = cnsttree(inttype, 0L);
}
t = gettok();
return p;
}
Tree idtree(Symbol p) {
int op;
Tree e;
Type ty = p->type ? unqual(p->type) : voidptype;
if (p->scope == GLOBAL || p->sclass == STATIC)
op = ADDRG;
else if (p->scope == PARAM) {
op = ADDRF;
if (isstruct(p->type) && !IR->wants_argb)
{
e = tree(mkop(op,voidptype), ptr(ptr(p->type)), NULL, NULL);
e->u.sym = p;
return rvalue(rvalue(e));
}
} else if (p->sclass == EXTERN) {
assert(p->u.alias);
p = p->u.alias;
op = ADDRG;
} else
op = ADDRL;
p->ref += refinc;
if (isarray(ty))
e = tree(mkop(op,voidptype), p->type, NULL, NULL);
else if (isfunc(ty))
e = tree(mkop(op,funcptype), p->type, NULL, NULL);
else
e = tree(mkop(op,voidptype), ptr(p->type), NULL, NULL);
e->u.sym = p;
if (isptr(e->type))
e = rvalue(e);
return e;
}
Tree rvalue(Tree p) {
Type ty = deref(p->type);
ty = unqual(ty);
return tree(mkop(INDIR,ty), ty, p, NULL);
}
Tree lvalue(Tree p) {
if (generic(p->op) != INDIR) {
error("lvalue required\n");
return value(p);
} else if (unqual(p->type) == voidtype)
warning("`%t' used as an lvalue\n", p->type);
return p->kids[0];
}
Tree retype(Tree p, Type ty) {
Tree q;
if (p->type == ty)
return p;
q = tree(p->op, ty, p->kids[0], p->kids[1]);
q->node = p->node;
q->u = p->u;
return q;
}
Tree rightkid(Tree p) {
while (p && p->op == RIGHT)
if (p->kids[1])
p = p->kids[1];
else if (p->kids[0])
p = p->kids[0];
else
assert(0);
assert(p);
return p;
}
int hascall(Tree p) {
if (p == 0)
return 0;
if (generic(p->op) == CALL || (IR->mulops_calls &&
(p->op == DIV+I || p->op == MOD+I || p->op == MUL+I
|| p->op == DIV+U || p->op == MOD+U || p->op == MUL+U)))
return 1;
return hascall(p->kids[0]) || hascall(p->kids[1]);
}
Type binary(Type xty, Type yty) {
#define xx(t) if (xty == t || yty == t) return t
xx(longdouble);
xx(doubletype);
xx(floattype);
xx(unsignedlonglong);
xx(longlong);
xx(unsignedlong);
if ((xty == longtype && yty == unsignedtype)
|| (xty == unsignedtype && yty == longtype)) {
if (longtype->size > unsignedtype->size)
return longtype;
else
return unsignedlong;
}
xx(longtype);
xx(unsignedtype);
return inttype;
#undef xx
}
Tree pointer(Tree p) {
if (isarray(p->type))
/* assert(p->op != RIGHT || p->u.sym == NULL), */
p = retype(p, atop(p->type));
else if (isfunc(p->type))
p = retype(p, ptr(p->type));
return p;
}
Tree cond(Tree p) {
int op = generic(rightkid(p)->op);
if (op == AND || op == OR || op == NOT
|| op == EQ || op == NE
|| op == LE || op == LT || op == GE || op == GT)
return p;
p = pointer(p);
return (*optree[NEQ])(NE, p, consttree(0, inttype));
}
Tree cast(Tree p, Type type) {
Type src, dst;
p = value(p);
if (p->type == type)
return p;
dst = unqual(type);
src = unqual(p->type);
if (src->op != dst->op || src->size != dst->size) {
switch (src->op) {
case INT:
if (src->size < inttype->size)
p = simplify(CVI, inttype, p, NULL);
break;
case UNSIGNED:
if (src->size < inttype->size)
p = simplify(CVU, inttype, p, NULL);
else if (src->size < unsignedtype->size)
p = simplify(CVU, unsignedtype, p, NULL);
break;
case ENUM:
p = retype(p, inttype);
break;
case POINTER:
if (isint(dst) && src->size > dst->size)
warning("conversion from `%t' to `%t' is undefined\n", p->type, type);
p = simplify(CVP, super(src), p, NULL);
break;
case FLOAT:
break;
default: assert(0);
}
{
src = unqual(p->type);
dst = super(dst);
if (src->op != dst->op)
switch (src->op) {
case INT:
p = simplify(CVI, dst, p, NULL);
break;
case UNSIGNED:
if (isfloat(dst)) {
Type ssrc = signedint(src);
Tree two = cnsttree(longdouble, (double)2.0);
p = (*optree['+'])(ADD,
(*optree['*'])(MUL,
two,
simplify(CVU, ssrc,
simplify(RSH, src,
p, consttree(1, inttype)), NULL)),
simplify(CVU, ssrc,
simplify(BAND, src,
p, consttree(1, unsignedtype)), NULL));
} else
p = simplify(CVU, dst, p, NULL);
break;
case FLOAT:
if (isunsigned(dst)) {
Type sdst = signedint(dst);
Tree c = cast(cnsttree(longdouble, (double)sdst->u.sym->u.limits.max.i + 1), src);
p = condtree(
simplify(GE, src, p, c),
(*optree['+'])(ADD,
cast(cast(simplify(SUB, src, p, c), sdst), dst),
cast(cnsttree(unsignedlong, (unsigned long)sdst->u.sym->u.limits.max.i + 1), dst)),
simplify(CVF, sdst, p, NULL));
} else
p = simplify(CVF, dst, p, NULL);
break;
default: assert(0);
}
dst = unqual(type);
}
}
src = unqual(p->type);
switch (src->op) {
case INT:
if (src->op != dst->op || src->size != dst->size)
p = simplify(CVI, dst, p, NULL);
break;
case UNSIGNED:
if (src->op != dst->op || src->size != dst->size)
p = simplify(CVU, dst, p, NULL);
break;
case FLOAT:
if (src->op != dst->op || src->size != dst->size)
p = simplify(CVF, dst, p, NULL);
break;
case POINTER:
if (src->op != dst->op)
p = simplify(CVP, dst, p, NULL);
else {
if ((isfunc(src->type) && !isfunc(dst->type))
|| (!isfunc(src->type) && isfunc(dst->type)))
warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, type);
if (src->size != dst->size)
p = simplify(CVP, dst, p, NULL);
}
break;
default: assert(0);
}
return retype(p, type);
}
Tree field(Tree p, const char *name) {
Field q;
Type ty1, ty = p->type;
if (isptr(ty))
ty = deref(ty);
ty1 = ty;
ty = unqual(ty);
if ((q = fieldref(name, ty)) != NULL) {
if (isarray(q->type)) {
ty = q->type->type;
if (isconst(ty1) && !isconst(ty))
ty = qual(CONST, ty);
if (isvolatile(ty1) && !isvolatile(ty))
ty = qual(VOLATILE, ty);
ty = array(ty, q->type->size/ty->size, q->type->align);
} else {
ty = q->type;
if (isconst(ty1) && !isconst(ty))
ty = qual(CONST, ty);
if (isvolatile(ty1) && !isvolatile(ty))
ty = qual(VOLATILE, ty);
ty = ptr(ty);
}
if (YYcheck && !isaddrop(p->op) && q->offset > 0) /* omit */
p = nullcall(ty, YYcheck, p, consttree(q->offset, inttype)); /* omit */
else /* omit */
p = simplify(ADD+P, ty, p, consttree(q->offset, inttype));
if (q->lsb) {
p = tree(FIELD, ty->type, rvalue(p), NULL);
p->u.field = q;
} else if (!isarray(q->type))
p = rvalue(p);
} else {
error("unknown field `%s' of `%t'\n", name, ty);
p = rvalue(retype(p, ptr(inttype)));
}
return p;
}
/* funcname - return name of function f or a function' */
char *funcname(Tree f) {
if (isaddrop(f->op))
return stringf("`%s'", f->u.sym->name);
return "a function";
}
static Tree nullcheck(Tree p) {
if (!needconst && YYnull && isptr(p->type)) {
p = value(p);
if (strcmp(YYnull->name, "_YYnull") == 0) {
Symbol t1 = temporary(REGISTER, voidptype);
p = tree(RIGHT, p->type,
tree(OR, voidtype,
cond(asgn(t1, cast(p, voidptype))),
vcall(YYnull, voidtype, (file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL)),
idtree(t1));
}
else
p = nullcall(p->type, YYnull, p, cnsttree(inttype, 0L));
}
return p;
}
Tree nullcall(Type pty, Symbol f, Tree p, Tree e) {
Type ty;
if (isarray(pty))
return retype(nullcall(atop(pty), f, p, e), pty);
ty = unqual(unqual(p->type)->type);
return vcall(f, pty,
p, e,
cnsttree(inttype, (long)ty->size),
cnsttree(inttype, (long)ty->align),
(file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno) , NULL);
}

View File

@@ -1,830 +0,0 @@
#include "c.h"
#define readsreg(p) \
(generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P)
#define setsrc(d) ((d) && (d)->x.regnode && \
(d)->x.regnode->set == src->x.regnode->set && \
(d)->x.regnode->mask&src->x.regnode->mask)
#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b))
static Symbol askfixedreg(Symbol);
static Symbol askreg(Symbol, unsigned*);
static void blkunroll(int, int, int, int, int, int, int[]);
static void docall(Node);
static void dumpcover(Node, int, int);
static void dumpregs(char *, char *, char *);
static void dumprule(int);
static void dumptree(Node);
static unsigned emitasm(Node, int);
static void genreload(Node, Symbol, int);
static void genspill(Symbol, Node, Symbol);
static Symbol getreg(Symbol, unsigned*, Node);
static int getrule(Node, int);
static void linearize(Node, Node);
static int moveself(Node);
static void prelabel(Node);
static Node* prune(Node, Node*);
static void putreg(Symbol);
static void ralloc(Node);
static void reduce(Node, int);
static int reprune(Node*, int, int, Node);
static int requate(Node);
static Node reuse(Node, int);
static void rewrite(Node);
static Symbol spillee(Symbol, unsigned mask[], Node);
static void spillr(Symbol, Node);
static int uses(Node, Regnode);
int offset;
int maxoffset;
int framesize;
int argoffset;
int maxargoffset;
int dalign, salign;
int bflag = 0; /* omit */
int dflag = 0;
int swap;
unsigned (*emitter)(Node, int) = emitasm;
static char NeedsReg[] = {
0, /* unused */
1, /* CNST */
0, 0, /* ARG ASGN */
1, /* INDIR */
0, 0, 1, 1, /* - - CVF CVI */
1, 0, 1, 1, /* CVP - CVU NEG */
1, /* CALL */
1, /* LOAD */
0, /* RET */
1, 1, 1, /* ADDRG ADDRF ADDRL */
1, 1, 1, 1, 1, /* ADD SUB LSH MOD RSH */
1, 1, 1, 1, /* BAND BCOM BOR BXOR */
1, 1, /* DIV MUL */
0, 0, 0, 0, 0, 0, /* EQ GE GT LE LT NE */
0, 0 /* JUMP LABEL */
};
Node head;
unsigned freemask[2];
unsigned usedmask[2];
unsigned tmask[2];
unsigned vmask[2];
Symbol mkreg(char *fmt, int n, int mask, int set) {
Symbol p;
NEW0(p, PERM);
p->name = p->x.name = stringf(fmt, n);
NEW0(p->x.regnode, PERM);
p->x.regnode->number = n;
p->x.regnode->mask = mask<<n;
p->x.regnode->set = set;
return p;
}
Symbol mkwildcard(Symbol *syms) {
Symbol p;
NEW0(p, PERM);
p->name = p->x.name = "wildcard";
p->x.wildcard = syms;
return p;
}
void mkauto(Symbol p) {
assert(p->sclass == AUTO);
offset = roundup(offset + p->type->size, p->type->align);
p->x.offset = -offset;
p->x.name = stringd(-offset);
}
void blockbeg(Env *e) {
e->offset = offset;
e->freemask[IREG] = freemask[IREG];
e->freemask[FREG] = freemask[FREG];
}
void blockend(Env *e) {
if (offset > maxoffset)
maxoffset = offset;
offset = e->offset;
freemask[IREG] = e->freemask[IREG];
freemask[FREG] = e->freemask[FREG];
}
int mkactual(int align, int size) {
int n = roundup(argoffset, align);
argoffset = n + size;
return n;
}
static void docall(Node p) {
p->syms[1] = p->syms[0];
p->syms[0] = intconst(argoffset);
if (argoffset > maxargoffset)
maxargoffset = argoffset;
argoffset = 0;
}
void blkcopy(int dreg, int doff, int sreg, int soff, int size, int tmp[]) {
assert(size >= 0);
if (size == 0)
return;
else if (size <= 2)
blkunroll(size, dreg, doff, sreg, soff, size, tmp);
else if (size == 3) {
blkunroll(2, dreg, doff, sreg, soff, 2, tmp);
blkunroll(1, dreg, doff+2, sreg, soff+2, 1, tmp);
}
else if (size <= 16) {
blkunroll(4, dreg, doff, sreg, soff, size&~3, tmp);
blkcopy(dreg, doff+(size&~3),
sreg, soff+(size&~3), size&3, tmp);
}
else
(*IR->x.blkloop)(dreg, doff, sreg, soff, size, tmp);
}
static void blkunroll(int k, int dreg, int doff, int sreg, int soff, int size, int tmp[]) {
int i;
assert(IR->x.max_unaligned_load);
if (k > IR->x.max_unaligned_load
&& (k > salign || k > dalign))
k = IR->x.max_unaligned_load;
for (i = 0; i+k < size; i += 2*k) {
(*IR->x.blkfetch)(k, soff+i, sreg, tmp[0]);
(*IR->x.blkfetch)(k, soff+i+k, sreg, tmp[1]);
(*IR->x.blkstore)(k, doff+i, dreg, tmp[0]);
(*IR->x.blkstore)(k, doff+i+k, dreg, tmp[1]);
}
if (i < size) {
(*IR->x.blkfetch)(k, i+soff, sreg, tmp[0]);
(*IR->x.blkstore)(k, i+doff, dreg, tmp[0]);
}
}
void parseflags(int argc, char *argv[]) {
int i;
for (i = 0; i < argc; i++)
if (strcmp(argv[i], "-d") == 0)
dflag = 1;
else if (strcmp(argv[i], "-b") == 0) /* omit */
bflag = 1; /* omit */
}
static int getrule(Node p, int nt) {
int rulenum;
assert(p);
rulenum = (*IR->x._rule)(p->x.state, nt);
if (!rulenum) {
fprint(stderr, "(%x->op=%s at %w is corrupt.)\n", p, opname(p->op), &src);
assert(0);
}
return rulenum;
}
static void reduce(Node p, int nt) {
int rulenum, i;
short *nts;
Node kids[10];
p = reuse(p, nt);
rulenum = getrule(p, nt);
nts = IR->x._nts[rulenum];
(*IR->x._kids)(p, rulenum, kids);
for (i = 0; nts[i]; i++)
reduce(kids[i], nts[i]);
if (IR->x._isinstruction[rulenum]) {
assert(p->x.inst == 0 || p->x.inst == nt);
p->x.inst = nt;
if (p->syms[RX] && p->syms[RX]->temporary) {
debug(fprint(stderr, "(using %s)\n", p->syms[RX]->name));
p->syms[RX]->x.usecount++;
}
}
}
static Node reuse(Node p, int nt) {
struct _state {
short cost[1];
};
Symbol r = p->syms[RX];
if (generic(p->op) == INDIR && p->kids[0]->op == VREG+P
&& r->u.t.cse && p->x.mayrecalc
&& ((struct _state*)r->u.t.cse->x.state)->cost[nt] == 0)
return r->u.t.cse;
else
return p;
}
int mayrecalc(Node p) {
int op;
assert(p && p->syms[RX]);
if (p->syms[RX]->u.t.cse == NULL)
return 0;
op = generic(p->syms[RX]->u.t.cse->op);
if (op == CNST || op == ADDRF || op == ADDRG || op == ADDRL) {
p->x.mayrecalc = 1;
return 1;
} else
return 0;
}
static Node *prune(Node p, Node pp[]) {
if (p == NULL)
return pp;
p->x.kids[0] = p->x.kids[1] = p->x.kids[2] = NULL;
if (p->x.inst == 0)
return prune(p->kids[1], prune(p->kids[0], pp));
else if (p->syms[RX] && p->syms[RX]->temporary
&& p->syms[RX]->x.usecount < 2) {
p->x.inst = 0;
debug(fprint(stderr, "(clobbering %s)\n", p->syms[RX]->name));
return prune(p->kids[1], prune(p->kids[0], pp));
}
else {
prune(p->kids[1], prune(p->kids[0], &p->x.kids[0]));
*pp = p;
return pp + 1;
}
}
#define ck(i) return (i) ? 0 : LBURG_MAX
int range(Node p, int lo, int hi) {
Symbol s = p->syms[0];
switch (specific(p->op)) {
case ADDRF+P:
case ADDRL+P: ck(s->x.offset >= lo && s->x.offset <= hi);
case CNST+I: ck(s->u.c.v.i >= lo && s->u.c.v.i <= hi);
case CNST+U: ck(s->u.c.v.u >= lo && s->u.c.v.u <= hi);
case CNST+P: ck(s->u.c.v.p == 0 && lo <= 0 && hi >= 0);
}
return LBURG_MAX;
}
static void dumptree(Node p) {
if (p->op == VREG+P && p->syms[0]) {
fprint(stderr, "VREGP(%s)", p->syms[0]->name);
return;
} else if (generic(p->op) == LOAD) {
fprint(stderr, "LOAD(");
dumptree(p->kids[0]);
fprint(stderr, ")");
return;
}
fprint(stderr, "%s(", opname(p->op));
switch (generic(p->op)) {
case CNST: case LABEL:
case ADDRG: case ADDRF: case ADDRL:
if (p->syms[0])
fprint(stderr, "%s", p->syms[0]->name);
break;
case RET:
if (p->kids[0])
dumptree(p->kids[0]);
break;
case CVF: case CVI: case CVP: case CVU: case JUMP:
case ARG: case BCOM: case NEG: case INDIR:
dumptree(p->kids[0]);
break;
case CALL:
if (optype(p->op) != B) {
dumptree(p->kids[0]);
break;
}
/* else fall thru */
case EQ: case NE: case GT: case GE: case LE: case LT:
case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH:
case ADD: case SUB: case DIV: case MUL: case MOD:
dumptree(p->kids[0]);
fprint(stderr, ", ");
dumptree(p->kids[1]);
break;
default: assert(0);
}
fprint(stderr, ")");
}
static void dumpcover(Node p, int nt, int in) {
int rulenum, i;
short *nts;
Node kids[10];
p = reuse(p, nt);
rulenum = getrule(p, nt);
nts = IR->x._nts[rulenum];
fprint(stderr, "dumpcover(%x) = ", p);
for (i = 0; i < in; i++)
fprint(stderr, " ");
dumprule(rulenum);
(*IR->x._kids)(p, rulenum, kids);
for (i = 0; nts[i]; i++)
dumpcover(kids[i], nts[i], in+1);
}
static void dumprule(int rulenum) {
assert(rulenum);
fprint(stderr, "%s / %s", IR->x._string[rulenum],
IR->x._templates[rulenum]);
if (!IR->x._isinstruction[rulenum])
fprint(stderr, "\n");
}
static unsigned emitasm(Node p, int nt) {
int rulenum;
short *nts;
char *fmt;
Node kids[10];
p = reuse(p, nt);
rulenum = getrule(p, nt);
nts = IR->x._nts[rulenum];
fmt = IR->x._templates[rulenum];
assert(fmt);
if (IR->x._isinstruction[rulenum] && p->x.emitted)
print("%s", p->syms[RX]->x.name);
else if (*fmt == '#')
(*IR->x.emit2)(p);
else {
if (*fmt == '?') {
fmt++;
assert(p->kids[0]);
if (p->syms[RX] == p->x.kids[0]->syms[RX])
while (*fmt++ != '\n')
;
}
for ((*IR->x._kids)(p, rulenum, kids); *fmt; fmt++)
if (*fmt != '%')
(void)putchar(*fmt);
else if (*++fmt == 'F')
print("%d", framesize);
else if (*fmt >= '0' && *fmt <= '9')
emitasm(kids[*fmt - '0'], nts[*fmt - '0']);
else if (*fmt >= 'a' && *fmt < 'a' + NELEMS(p->syms))
fputs(p->syms[*fmt - 'a']->x.name, stdout);
else
(void)putchar(*fmt);
}
return 0;
}
void emit(Node p) {
for (; p; p = p->x.next) {
assert(p->x.registered);
if ((p->x.equatable && requate(p)) || moveself(p))
;
else
(*emitter)(p, p->x.inst);
p->x.emitted = 1;
}
}
static int moveself(Node p) {
return p->x.copy
&& p->syms[RX]->x.name == p->x.kids[0]->syms[RX]->x.name;
}
int move(Node p) {
p->x.copy = 1;
return 1;
}
static int requate(Node q) {
Symbol src = q->x.kids[0]->syms[RX];
Symbol tmp = q->syms[RX];
Node p;
int n = 0;
debug(fprint(stderr, "(requate(%x): tmp=%s src=%s)\n", q, tmp->x.name, src->x.name));
for (p = q->x.next; p; p = p->x.next)
if (p->x.copy && p->syms[RX] == src
&& p->x.kids[0]->syms[RX] == tmp)
debug(fprint(stderr, "(requate arm 0 at %x)\n", p)),
p->syms[RX] = tmp;
else if (setsrc(p->syms[RX]) && !moveself(p) && !readsreg(p))
return 0;
else if (p->x.spills)
return 0;
else if (generic(p->op) == CALL && p->x.next)
return 0;
else if (p->op == LABEL+V && p->x.next)
return 0;
else if (p->syms[RX] == tmp && readsreg(p))
debug(fprint(stderr, "(requate arm 5 at %x)\n", p)),
n++;
else if (p->syms[RX] == tmp)
break;
debug(fprint(stderr, "(requate arm 7 at %x)\n", p));
assert(n > 0);
for (p = q->x.next; p; p = p->x.next)
if (p->syms[RX] == tmp && readsreg(p)) {
p->syms[RX] = src;
if (--n <= 0)
break;
}
return 1;
}
static void prelabel(Node p) {
if (p == NULL)
return;
prelabel(p->kids[0]);
prelabel(p->kids[1]);
if (NeedsReg[opindex(p->op)])
setreg(p, (*IR->x.rmap)(opkind(p->op)));
switch (generic(p->op)) {
case ADDRF: case ADDRL:
if (p->syms[0]->sclass == REGISTER)
p->op = VREG+P;
break;
case INDIR:
if (p->kids[0]->op == VREG+P)
setreg(p, p->kids[0]->syms[0]);
break;
case ASGN:
if (p->kids[0]->op == VREG+P)
rtarget(p, 1, p->kids[0]->syms[0]);
break;
case CVI: case CVU: case CVP:
if (optype(p->op) != F
&& opsize(p->op) <= p->syms[0]->u.c.v.i)
p->op = LOAD + opkind(p->op);
break;
}
(IR->x.target)(p);
}
void setreg(Node p, Symbol r) {
p->syms[RX] = r;
}
void rtarget(Node p, int n, Symbol r) {
Node q = p->kids[n];
assert(q);
assert(r);
assert(r->sclass == REGISTER || !r->x.wildcard);
assert(q->syms[RX]);
if (r != q->syms[RX] && !q->syms[RX]->x.wildcard) {
q = newnode(LOAD + opkind(q->op),
q, NULL, q->syms[0]);
if (r->u.t.cse == p->kids[n])
r->u.t.cse = q;
p->kids[n] = p->x.kids[n] = q;
q->x.kids[0] = q->kids[0];
}
setreg(q, r);
debug(fprint(stderr, "(targeting %x->x.kids[%d]=%x to %s)\n", p, n, p->kids[n], r->x.name));
}
static void rewrite(Node p) {
assert(p->x.inst == 0);
prelabel(p);
debug(dumptree(p));
debug(fprint(stderr, "\n"));
(*IR->x._label)(p);
debug(dumpcover(p, 1, 0));
reduce(p, 1);
}
Node gen(Node forest) {
int i;
struct node sentinel;
Node dummy, p;
head = forest;
for (p = forest; p; p = p->link) {
assert(p->count == 0);
if (generic(p->op) == CALL)
docall(p);
else if ( generic(p->op) == ASGN
&& generic(p->kids[1]->op) == CALL)
docall(p->kids[1]);
else if (generic(p->op) == ARG)
(*IR->x.doarg)(p);
rewrite(p);
p->x.listed = 1;
}
for (p = forest; p; p = p->link)
prune(p, &dummy);
relink(&sentinel, &sentinel);
for (p = forest; p; p = p->link)
linearize(p, &sentinel);
forest = sentinel.x.next;
assert(forest);
sentinel.x.next->x.prev = NULL;
sentinel.x.prev->x.next = NULL;
for (p = forest; p; p = p->x.next)
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
assert(p->x.kids[i]->syms[RX]);
if (p->x.kids[i]->syms[RX]->temporary) {
p->x.kids[i]->x.prevuse =
p->x.kids[i]->syms[RX]->x.lastuse;
p->x.kids[i]->syms[RX]->x.lastuse = p->x.kids[i];
}
}
for (p = forest; p; p = p->x.next) {
ralloc(p);
if (p->x.listed && NeedsReg[opindex(p->op)]
&& (*IR->x.rmap)(opkind(p->op))) {
assert(generic(p->op) == CALL || generic(p->op) == LOAD);
putreg(p->syms[RX]);
}
}
return forest;
}
int notarget(Node p) {
return p->syms[RX]->x.wildcard ? 0 : LBURG_MAX;
}
static void putreg(Symbol r) {
assert(r && r->x.regnode);
freemask[r->x.regnode->set] |= r->x.regnode->mask;
debug(dumpregs("(freeing %s)\n", r->x.name, NULL));
}
static Symbol askfixedreg(Symbol s) {
Regnode r = s->x.regnode;
int n = r->set;
if (r->mask&~freemask[n])
return NULL;
else {
freemask[n] &= ~r->mask;
usedmask[n] |= r->mask;
return s;
}
}
static Symbol askreg(Symbol rs, unsigned rmask[]) {
int i;
if (rs->x.wildcard == NULL)
return askfixedreg(rs);
for (i = 31; i >= 0; i--) {
Symbol r = rs->x.wildcard[i];
if (r != NULL
&& !(r->x.regnode->mask&~rmask[r->x.regnode->set])
&& askfixedreg(r))
return r;
}
return NULL;
}
static Symbol getreg(Symbol s, unsigned mask[], Node p) {
Symbol r = askreg(s, mask);
if (r == NULL) {
r = spillee(s, mask, p);
assert(r && r->x.regnode);
spill(r->x.regnode->mask, r->x.regnode->set, p);
r = askreg(s, mask);
}
assert(r && r->x.regnode);
r->x.regnode->vbl = NULL;
return r;
}
int askregvar(Symbol p, Symbol regs) {
Symbol r;
assert(p);
if (p->sclass != REGISTER)
return 0;
else if (!isscalar(p->type)) {
p->sclass = AUTO;
return 0;
}
else if (p->temporary) {
p->x.name = "?";
return 1;
}
else if ((r = askreg(regs, vmask)) != NULL) {
p->x.regnode = r->x.regnode;
p->x.regnode->vbl = p;
p->x.name = r->x.name;
debug(dumpregs("(allocating %s to symbol %s)\n", p->x.name, p->name));
return 1;
}
else {
p->sclass = AUTO;
return 0;
}
}
static void linearize(Node p, Node next) {
int i;
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++)
linearize(p->x.kids[i], next);
relink(next->x.prev, p);
relink(p, next);
debug(fprint(stderr, "(listing %x)\n", p));
}
static void ralloc(Node p) {
int i;
unsigned mask[2];
mask[0] = tmask[0];
mask[1] = tmask[1];
assert(p);
debug(fprint(stderr, "(rallocing %x)\n", p));
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
Node kid = p->x.kids[i];
Symbol r = kid->syms[RX];
assert(r && kid->x.registered);
if (r->sclass != REGISTER && r->x.lastuse == kid)
putreg(r);
}
if (!p->x.registered && NeedsReg[opindex(p->op)]
&& (*IR->x.rmap)(opkind(p->op))) {
Symbol sym = p->syms[RX], set = sym;
assert(sym);
if (sym->temporary)
set = (*IR->x.rmap)(opkind(p->op));
assert(set);
if (set->sclass != REGISTER) {
Symbol r;
if (*IR->x._templates[getrule(p, p->x.inst)] == '?')
for (i = 1; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
Symbol r = p->x.kids[i]->syms[RX];
assert(p->x.kids[i]->x.registered);
assert(r && r->x.regnode);
assert(sym->x.wildcard || sym != r);
mask[r->x.regnode->set] &= ~r->x.regnode->mask;
}
r = getreg(set, mask, p);
if (sym->temporary) {
Node q;
r->x.lastuse = sym->x.lastuse;
for (q = sym->x.lastuse; q; q = q->x.prevuse) {
q->syms[RX] = r;
q->x.registered = 1;
if (sym->u.t.cse && q->x.copy)
q->x.equatable = 1;
}
} else {
p->syms[RX] = r;
r->x.lastuse = p;
}
debug(dumpregs("(allocating %s to node %x)\n", r->x.name, (char *) p));
}
}
p->x.registered = 1;
(*IR->x.clobber)(p);
}
static Symbol spillee(Symbol set, unsigned mask[], Node here) {
Symbol bestreg = NULL;
int bestdist = -1, i;
assert(set);
if (!set->x.wildcard)
bestreg = set;
else {
for (i = 31; i >= 0; i--) {
Symbol ri = set->x.wildcard[i];
if (
ri != NULL &&
ri->x.lastuse &&
(ri->x.regnode->mask&tmask[ri->x.regnode->set]&mask[ri->x.regnode->set])
) {
Regnode rn = ri->x.regnode;
Node q = here;
int dist = 0;
for (; q && !uses(q, rn); q = q->x.next)
dist++;
if (q && dist > bestdist) {
bestdist = dist;
bestreg = ri;
}
}
}
}
assert(bestreg); /* Must be able to spill something. Reconfigure the register allocator
to ensure that we can allocate a register for all nodes without spilling
the node's necessary input regs. */
assert(bestreg->x.regnode->vbl == NULL); /* Can't spill register variables because
the reload site might be in other blocks. Reconfigure the register allocator
to ensure that this register is never allocated to a variable. */
return bestreg;
}
static int uses(Node p, Regnode rn) {
int i;
for (i = 0; i < NELEMS(p->x.kids); i++)
if (
p->x.kids[i] &&
p->x.kids[i]->x.registered &&
rn->set == p->x.kids[i]->syms[RX]->x.regnode->set &&
(rn->mask&p->x.kids[i]->syms[RX]->x.regnode->mask)
)
return 1;
return 0;
}
static void spillr(Symbol r, Node here) {
int i;
Symbol tmp;
Node p = r->x.lastuse;
assert(p);
while (p->x.prevuse)
assert(r == p->syms[RX]),
p = p->x.prevuse;
assert(p->x.registered && !readsreg(p));
tmp = newtemp(AUTO, optype(p->op), opsize(p->op));
genspill(r, p, tmp);
for (p = here->x.next; p; p = p->x.next)
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
Node k = p->x.kids[i];
if (k->x.registered && k->syms[RX] == r)
genreload(p, tmp, i);
}
putreg(r);
}
static void genspill(Symbol r, Node last, Symbol tmp) {
Node p, q;
Symbol s;
unsigned ty;
debug(fprint(stderr, "(spilling %s to local %s)\n", r->x.name, tmp->x.name));
debug(fprint(stderr, "(genspill: "));
debug(dumptree(last));
debug(fprint(stderr, ")\n"));
ty = opkind(last->op);
NEW0(s, FUNC);
s->sclass = REGISTER;
s->name = s->x.name = r->x.name;
s->x.regnode = r->x.regnode;
q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, s);
q = newnode(INDIR + ty, q, NULL, NULL);
p = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp);
p = newnode(ASGN + ty, p, q, NULL);
p->x.spills = 1;
rewrite(p);
prune(p, &q);
q = last->x.next;
linearize(p, q);
for (p = last->x.next; p != q; p = p->x.next) {
ralloc(p);
assert(!p->x.listed || !NeedsReg[opindex(p->op)] || !(*IR->x.rmap)(opkind(p->op)));
}
}
static void genreload(Node p, Symbol tmp, int i) {
Node q;
int ty;
debug(fprint(stderr, "(replacing %x with a reload from %s)\n", p->x.kids[i], tmp->x.name));
debug(fprint(stderr, "(genreload: "));
debug(dumptree(p->x.kids[i]));
debug(fprint(stderr, ")\n"));
ty = opkind(p->x.kids[i]->op);
q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp);
p->x.kids[i] = newnode(INDIR + ty, q, NULL, NULL);
rewrite(p->x.kids[i]);
prune(p->x.kids[i], &q);
reprune(&p->kids[1], reprune(&p->kids[0], 0, i, p), i, p);
prune(p, &q);
linearize(p->x.kids[i], p);
}
static int reprune(Node *pp, int k, int n, Node p) {
struct node x, *q = *pp;
if (q == NULL || k > n)
return k;
else if (q->x.inst == 0)
return reprune(&q->kids[1],
reprune(&q->kids[0], k, n, p), n, p);
if (k == n) {
debug(fprint(stderr, "(reprune changes %x from %x to %x)\n", pp, *pp, p->x.kids[n]));
*pp = p->x.kids[n];
x = *p;
(IR->x.target)(&x);
}
return k + 1;
}
void spill(unsigned mask, int n, Node here) {
int i;
Node p;
here->x.spills = 1;
usedmask[n] |= mask;
if (mask&~freemask[n]) {
assert( /* It makes no sense for a node to clobber() its target. */
here->x.registered == 0 || /* call isn't coming through clobber() */
here->syms[RX] == NULL ||
here->syms[RX]->x.regnode == NULL ||
here->syms[RX]->x.regnode->set != n ||
(here->syms[RX]->x.regnode->mask&mask) == 0
);
for (p = here; p; p = p->x.next)
for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) {
Symbol r = p->x.kids[i]->syms[RX];
assert(r);
if (p->x.kids[i]->x.registered && r->x.regnode->set == n
&& r->x.regnode->mask&mask)
spillr(r, here);
}
}
}
static void dumpregs(char *msg, char *a, char *b) {
fprint(stderr, msg, a, b);
fprint(stderr, "(free[0]=%x)\n", freemask[0]);
fprint(stderr, "(free[1]=%x)\n", freemask[1]);
}
int getregnum(Node p) {
assert(p && p->syms[RX] && p->syms[RX]->x.regnode);
return p->syms[RX]->x.regnode->number;
}
unsigned regloc(Symbol p) {
assert(p && p->sclass == REGISTER && p->sclass == REGISTER && p->x.regnode);
return p->x.regnode->set<<8 | p->x.regnode->number;
}

View File

@@ -1,318 +0,0 @@
#include "c.h"
static int curseg; /* current segment */
/* defpointer - initialize a pointer to p or to 0 if p==0 */
void defpointer(Symbol p) {
if (p) {
(*IR->defaddress)(p);
p->ref++;
} else {
static Value v;
(*IR->defconst)(P, voidptype->size, v);
}
}
/* genconst - generate/check constant expression e; return size */
static int genconst(Tree e, int def) {
for (;;)
switch (generic(e->op)) {
case ADDRG:
if (def)
(*IR->defaddress)(e->u.sym);
return e->type->size;
case CNST:
if (e->op == CNST+P && isarray(e->type)) {
e = cvtconst(e);
continue;
}
if (def)
(*IR->defconst)(e->type->op, e->type->size, e->u.v);
return e->type->size;
case RIGHT:
assert(e->kids[0] || e->kids[1]);
if (e->kids[1] && e->kids[0])
error("initializer must be constant\n");
e = e->kids[1] ? e->kids[1] : e->kids[0];
continue;
case CVP:
if (isarith(e->type))
error("cast from `%t' to `%t' is illegal in constant expressions\n",
e->kids[0]->type, e->type);
/* fall thru */
case CVI: case CVU: case CVF:
e = e->kids[0];
continue;
default:
error("initializer must be constant\n");
if (def)
genconst(consttree(0, inttype), def);
return inttype->size;
}
}
/* initvalue - evaluate a constant expression for a value of integer type ty */
static Tree initvalue(Type ty) {
Type aty;
Tree e;
needconst++;
e = expr1(0);
if ((aty = assign(ty, e)) != NULL)
e = cast(e, aty);
else {
error("invalid initialization type; found `%t' expected `%t'\n",
e->type, ty);
e = retype(consttree(0, inttype), ty);
}
needconst--;
if (generic(e->op) != CNST) {
error("initializer must be constant\n");
e = retype(consttree(0, inttype), ty);
}
return e;
}
/* initarray - initialize array of ty of <= len bytes; if len == 0, go to } */
static int initarray(int len, Type ty, int lev) {
int n = 0;
do {
initializer(ty, lev);
n += ty->size;
if ((len > 0 && n >= len) || t != ',')
break;
t = gettok();
} while (t != '}');
return n;
}
/* initchar - initialize array of <= len ty characters; if len == 0, go to } */
static int initchar(int len, Type ty) {
int n = 0;
char buf[16], *s = buf;
do {
*s++ = initvalue(ty)->u.v.i;
if (++n%inttype->size == 0) {
(*IR->defstring)(inttype->size, buf);
s = buf;
}
if ((len > 0 && n >= len) || t != ',')
break;
t = gettok();
} while (t != '}');
if (s > buf)
(*IR->defstring)(s - buf, buf);
return n;
}
/* initend - finish off an initialization at level lev; accepts trailing comma */
static void initend(int lev, char follow[]) {
if (lev == 0 && t == ',')
t = gettok();
test('}', follow);
}
/* initfields - initialize <= an unsigned's worth of bit fields in fields p to q */
static int initfields(Field p, Field q) {
unsigned int bits = 0;
int i, n = 0;
do {
i = initvalue(inttype)->u.v.i;
if (fieldsize(p) < 8*p->type->size) {
if ((p->type == inttype &&
(i < -(int)(fieldmask(p)>>1)-1 || i > (int)(fieldmask(p)>>1)))
|| (p->type == unsignedtype && (i&~fieldmask(p)) != 0))
warning("initializer exceeds bit-field width\n");
i &= fieldmask(p);
}
bits |= i<<fieldright(p);
if (IR->little_endian) {
if (fieldsize(p) + fieldright(p) > n)
n = fieldsize(p) + fieldright(p);
} else {
if (fieldsize(p) + fieldleft(p) > n)
n = fieldsize(p) + fieldleft(p);
}
if (p->link == q)
break;
p = p->link;
} while (t == ',' && (t = gettok()) != 0);
n = (n + 7)/8;
for (i = 0; i < n; i++) {
Value v;
if (IR->little_endian) {
v.u = (unsigned char)bits;
bits >>= 8;
} else { /* a big endian */
v.u = (unsigned char)(bits>>(8*(unsignedtype->size - 1)));
bits <<= 8;
}
(*IR->defconst)(U, unsignedchar->size, v);
}
return n;
}
/* initstruct - initialize a struct ty of <= len bytes; if len == 0, go to } */
static int initstruct(int len, Type ty, int lev) {
int a, n = 0;
Field p = ty->u.sym->u.s.flist;
do {
if (p->offset > n) {
(*IR->space)(p->offset - n);
n += p->offset - n;
}
if (p->lsb) {
Field q = p;
while (q->link && q->link->offset == p->offset)
q = q->link;
n += initfields(p, q->link);
p = q;
} else {
initializer(p->type, lev);
n += p->type->size;
}
if (p->link) {
p = p->link;
a = p->type->align;
} else
a = ty->align;
if (a && n%a) {
(*IR->space)(a - n%a);
n = roundup(n, a);
}
if ((len > 0 && n >= len) || t != ',')
break;
t = gettok();
} while (t != '}');
return n;
}
/* initializer - constexpr | { constexpr ( , constexpr )* [ , ] } */
Type initializer(Type ty, int lev) {
int n = 0;
Tree e;
Type aty = NULL;
static char follow[] = { IF, CHAR, STATIC, 0 };
ty = unqual(ty);
if (isscalar(ty)) {
needconst++;
if (t == '{') {
t = gettok();
e = expr1(0);
initend(lev, follow);
} else
e = expr1(0);
e = pointer(e);
if ((aty = assign(ty, e)) != NULL)
e = cast(e, aty);
else
error("invalid initialization type; found `%t' expected `%t'\n",
e->type, ty);
n = genconst(e, 1);
deallocate(STMT);
needconst--;
}
if ((isunion(ty) || isstruct(ty)) && ty->size == 0) {
static char follow[] = { CHAR, STATIC, 0 };
error("cannot initialize undefined `%t'\n", ty);
skipto(';', follow);
return ty;
} else if (isunion(ty)) {
if (t == '{') {
t = gettok();
n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
initend(lev, follow);
} else {
if (lev == 0)
error("missing { in initialization of `%t'\n", ty);
n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
}
} else if (isstruct(ty)) {
if (t == '{') {
t = gettok();
n = initstruct(0, ty, lev + 1);
test('}', follow);
} else if (lev > 0)
n = initstruct(ty->size, ty, lev + 1);
else {
error("missing { in initialization of `%t'\n", ty);
n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
}
}
if (isarray(ty))
aty = unqual(ty->type);
if (isarray(ty) && ischar(aty)) {
if (t == SCON) {
if (ty->size > 0 && ty->size == tsym->type->size - 1)
tsym->type = array(chartype, ty->size, 0);
n = tsym->type->size;
(*IR->defstring)(tsym->type->size, tsym->u.c.v.p);
t = gettok();
} else if (t == '{') {
t = gettok();
if (t == SCON) {
ty = initializer(ty, lev + 1);
initend(lev, follow);
return ty;
}
n = initchar(0, aty);
test('}', follow);
} else if (lev > 0 && ty->size > 0)
n = initchar(ty->size, aty);
else { /* eg, char c[] = 0; */
error("missing { in initialization of `%t'\n", ty);
n = initchar(1, aty);
}
} else if (isarray(ty)) {
if (t == SCON && aty == widechar) {
int i;
unsigned int *s = tsym->u.c.v.p;
if (ty->size > 0 && ty->size == tsym->type->size - widechar->size)
tsym->type = array(widechar, ty->size/widechar->size, 0);
n = tsym->type->size;
for (i = 0; i < n; i += widechar->size) {
Value v;
v.u = *s++;
(*IR->defconst)(widechar->op, widechar->size, v);
}
t = gettok();
} else if (t == '{') {
t = gettok();
if (t == SCON && aty == widechar) {
ty = initializer(ty, lev + 1);
initend(lev, follow);
return ty;
}
n = initarray(0, aty, lev + 1);
test('}', follow);
} else if (lev > 0 && ty->size > 0)
n = initarray(ty->size, aty, lev + 1);
else {
error("missing { in initialization of `%t'\n", ty);
n = initarray(aty->size, aty, lev + 1);
}
}
if (ty->size) {
if (n > ty->size)
error("too many initializers\n");
else if (n < ty->size)
(*IR->space)(ty->size - n);
} else if (isarray(ty) && ty->type->size > 0)
ty = array(ty->type, n/ty->type->size, 0);
else
ty->size = n;
return ty;
}
/* swtoseg - switch to segment seg, if necessary */
void swtoseg(int seg) {
if (curseg != seg)
(*IR->segment)(seg);
curseg = seg;
}

View File

@@ -1,7 +0,0 @@
void init(int argc, char *argv[]) {
{extern void input_init(int, char *[]); input_init(argc, argv);}
{extern void main_init(int, char *[]); main_init(argc, argv);}
{extern void prof_init(int, char *[]); prof_init(argc, argv);}
{extern void trace_init(int, char *[]); trace_init(argc, argv);}
{extern void type_init(int, char *[]); type_init(argc, argv);}
}

View File

@@ -1,135 +0,0 @@
#include "c.h"
static void pragma(void);
static void resynch(void);
static int bsize;
static unsigned char buffer[MAXLINE+1 + BUFSIZE+1];
unsigned char *cp; /* current input character */
char *file; /* current input file name */
char *firstfile; /* first input file */
unsigned char *limit; /* points to last character + 1 */
char *line; /* current line */
int lineno; /* line number of current line */
void nextline(void) {
do {
if (cp >= limit) {
fillbuf();
if (cp >= limit)
cp = limit;
if (cp == limit)
return;
} else {
lineno++;
for (line = (char *)cp; *cp==' ' || *cp=='\t'; cp++)
;
if (*cp == '#') {
resynch();
nextline();
}
}
} while (*cp == '\n' && cp == limit);
}
void fillbuf(void) {
if (bsize == 0)
return;
if (cp >= limit)
cp = &buffer[MAXLINE+1];
else
{
int n = limit - cp;
unsigned char *s = &buffer[MAXLINE+1] - n;
assert(s >= buffer);
line = (char *)s - ((char *)cp - line);
while (cp < limit)
*s++ = *cp++;
cp = &buffer[MAXLINE+1] - n;
}
if (feof(stdin))
bsize = 0;
else
bsize = fread(&buffer[MAXLINE+1], 1, BUFSIZE, stdin);
if (bsize < 0) {
error("read error\n");
exit(EXIT_FAILURE);
}
limit = &buffer[MAXLINE+1+bsize];
*limit = '\n';
}
void input_init(int argc, char *argv[]) {
static int inited;
if (inited)
return;
inited = 1;
main_init(argc, argv);
limit = cp = &buffer[MAXLINE+1];
bsize = -1;
lineno = 0;
file = NULL;
fillbuf();
if (cp >= limit)
cp = limit;
nextline();
}
/* pragma - handle #pragma ref id... */
static void pragma(void) {
if ((t = gettok()) == ID && strcmp(token, "ref") == 0)
for (;;) {
while (*cp == ' ' || *cp == '\t')
cp++;
if (*cp == '\n' || *cp == 0)
break;
if ((t = gettok()) == ID && tsym) {
tsym->ref++;
use(tsym, src);
}
}
}
/* resynch - set line number/file name in # n [ "file" ] and #pragma ... */
static void resynch(void) {
for (cp++; *cp == ' ' || *cp == '\t'; )
cp++;
if (limit - cp < MAXLINE)
fillbuf();
if (strncmp((char *)cp, "pragma", 6) == 0) {
cp += 6;
pragma();
} else if (*cp >= '0' && *cp <= '9') {
line: for (lineno = 0; *cp >= '0' && *cp <= '9'; )
lineno = 10*lineno + *cp++ - '0';
lineno--;
while (*cp == ' ' || *cp == '\t')
cp++;
if (*cp == '"') {
file = (char *)++cp;
while (*cp && *cp != '"' && *cp != '\n')
cp++;
file = stringn(file, (char *)cp - file);
if (*cp == '\n')
warning("missing \" in preprocessor line\n");
if (firstfile == 0)
firstfile = file;
}
} else if (strncmp((char *)cp, "line", 4) == 0) {
for (cp += 4; *cp == ' ' || *cp == '\t'; )
cp++;
if (*cp >= '0' && *cp <= '9')
goto line;
if (Aflag >= 2)
warning("unrecognized control line\n");
} else if (Aflag >= 2 && *cp != '\n')
warning("unrecognized control line\n");
while (*cp)
if (*cp++ == '\n') {
if (cp == limit + 1)
nextline();
else
break;
}
}

View File

@@ -1,923 +0,0 @@
#include "c.h"
#include <float.h>
#include <errno.h>
#define MAXTOKEN 32
enum { BLANK=01, NEWLINE=02, LETTER=04,
DIGIT=010, HEX=020, OTHER=040 };
static unsigned char map[256] = { /* 000 nul */ 0,
/* 001 soh */ 0,
/* 002 stx */ 0,
/* 003 etx */ 0,
/* 004 eot */ 0,
/* 005 enq */ 0,
/* 006 ack */ 0,
/* 007 bel */ 0,
/* 010 bs */ 0,
/* 011 ht */ BLANK,
/* 012 nl */ NEWLINE,
/* 013 vt */ BLANK,
/* 014 ff */ BLANK,
/* 015 cr */ 0,
/* 016 so */ 0,
/* 017 si */ 0,
/* 020 dle */ 0,
/* 021 dc1 */ 0,
/* 022 dc2 */ 0,
/* 023 dc3 */ 0,
/* 024 dc4 */ 0,
/* 025 nak */ 0,
/* 026 syn */ 0,
/* 027 etb */ 0,
/* 030 can */ 0,
/* 031 em */ 0,
/* 032 sub */ 0,
/* 033 esc */ 0,
/* 034 fs */ 0,
/* 035 gs */ 0,
/* 036 rs */ 0,
/* 037 us */ 0,
/* 040 sp */ BLANK,
/* 041 ! */ OTHER,
/* 042 " */ OTHER,
/* 043 # */ OTHER,
/* 044 $ */ 0,
/* 045 % */ OTHER,
/* 046 & */ OTHER,
/* 047 ' */ OTHER,
/* 050 ( */ OTHER,
/* 051 ) */ OTHER,
/* 052 * */ OTHER,
/* 053 + */ OTHER,
/* 054 , */ OTHER,
/* 055 - */ OTHER,
/* 056 . */ OTHER,
/* 057 / */ OTHER,
/* 060 0 */ DIGIT,
/* 061 1 */ DIGIT,
/* 062 2 */ DIGIT,
/* 063 3 */ DIGIT,
/* 064 4 */ DIGIT,
/* 065 5 */ DIGIT,
/* 066 6 */ DIGIT,
/* 067 7 */ DIGIT,
/* 070 8 */ DIGIT,
/* 071 9 */ DIGIT,
/* 072 : */ OTHER,
/* 073 ; */ OTHER,
/* 074 < */ OTHER,
/* 075 = */ OTHER,
/* 076 > */ OTHER,
/* 077 ? */ OTHER,
/* 100 @ */ 0,
/* 101 A */ LETTER|HEX,
/* 102 B */ LETTER|HEX,
/* 103 C */ LETTER|HEX,
/* 104 D */ LETTER|HEX,
/* 105 E */ LETTER|HEX,
/* 106 F */ LETTER|HEX,
/* 107 G */ LETTER,
/* 110 H */ LETTER,
/* 111 I */ LETTER,
/* 112 J */ LETTER,
/* 113 K */ LETTER,
/* 114 L */ LETTER,
/* 115 M */ LETTER,
/* 116 N */ LETTER,
/* 117 O */ LETTER,
/* 120 P */ LETTER,
/* 121 Q */ LETTER,
/* 122 R */ LETTER,
/* 123 S */ LETTER,
/* 124 T */ LETTER,
/* 125 U */ LETTER,
/* 126 V */ LETTER,
/* 127 W */ LETTER,
/* 130 X */ LETTER,
/* 131 Y */ LETTER,
/* 132 Z */ LETTER,
/* 133 [ */ OTHER,
/* 134 \ */ OTHER,
/* 135 ] */ OTHER,
/* 136 ^ */ OTHER,
/* 137 _ */ LETTER,
/* 140 ` */ 0,
/* 141 a */ LETTER|HEX,
/* 142 b */ LETTER|HEX,
/* 143 c */ LETTER|HEX,
/* 144 d */ LETTER|HEX,
/* 145 e */ LETTER|HEX,
/* 146 f */ LETTER|HEX,
/* 147 g */ LETTER,
/* 150 h */ LETTER,
/* 151 i */ LETTER,
/* 152 j */ LETTER,
/* 153 k */ LETTER,
/* 154 l */ LETTER,
/* 155 m */ LETTER,
/* 156 n */ LETTER,
/* 157 o */ LETTER,
/* 160 p */ LETTER,
/* 161 q */ LETTER,
/* 162 r */ LETTER,
/* 163 s */ LETTER,
/* 164 t */ LETTER,
/* 165 u */ LETTER,
/* 166 v */ LETTER,
/* 167 w */ LETTER,
/* 170 x */ LETTER,
/* 171 y */ LETTER,
/* 172 z */ LETTER,
/* 173 { */ OTHER,
/* 174 | */ OTHER,
/* 175 } */ OTHER,
/* 176 ~ */ OTHER, };
static struct symbol tval;
static char cbuf[BUFSIZE+1];
static unsigned int wcbuf[BUFSIZE+1];
Coordinate src; /* current source coordinate */
int t;
char *token; /* current token */
Symbol tsym; /* symbol table entry for current token */
static void *cput(int c, void *cl);
static void *wcput(int c, void *cl);
static void *scon(int q, void *put(int c, void *cl), void *cl);
static int backslash(int q);
static Symbol fcon(void);
static Symbol icon(unsigned long, int, int);
static void ppnumber(char *);
int gettok(void) {
for (;;) {
register unsigned char *rcp = cp;
while (map[*rcp]&BLANK)
rcp++;
if (limit - rcp < MAXTOKEN) {
cp = rcp;
fillbuf();
rcp = cp;
}
src.file = file;
src.x = (char *)rcp - line;
src.y = lineno;
cp = rcp + 1;
switch (*rcp++) {
case '/': if (*rcp == '*') {
int c = 0;
for (rcp++; *rcp != '/' || c != '*'; )
if (map[*rcp]&NEWLINE) {
if (rcp < limit)
c = *rcp;
cp = rcp + 1;
nextline();
rcp = cp;
if (rcp == limit)
break;
} else
c = *rcp++;
if (rcp < limit)
rcp++;
else
error("unclosed comment\n");
cp = rcp;
continue;
}
return '/';
case '<':
if (*rcp == '=') return cp++, LEQ;
if (*rcp == '<') return cp++, LSHIFT;
return '<';
case '>':
if (*rcp == '=') return cp++, GEQ;
if (*rcp == '>') return cp++, RSHIFT;
return '>';
case '-':
if (*rcp == '>') return cp++, DEREF;
if (*rcp == '-') return cp++, DECR;
return '-';
case '=': return *rcp == '=' ? cp++, EQL : '=';
case '!': return *rcp == '=' ? cp++, NEQ : '!';
case '|': return *rcp == '|' ? cp++, OROR : '|';
case '&': return *rcp == '&' ? cp++, ANDAND : '&';
case '+': return *rcp == '+' ? cp++, INCR : '+';
case ';': case ',': case ':':
case '*': case '~': case '%': case '^': case '?':
case '[': case ']': case '{': case '}': case '(': case ')':
return rcp[-1];
case '\n': case '\v': case '\r': case '\f':
nextline();
if (cp == limit) {
tsym = NULL;
return EOI;
}
continue;
case 'i':
if (rcp[0] == 'f'
&& !(map[rcp[1]]&(DIGIT|LETTER))) {
cp = rcp + 1;
return IF;
}
if (rcp[0] == 'n'
&& rcp[1] == 't'
&& !(map[rcp[2]]&(DIGIT|LETTER))) {
cp = rcp + 2;
tsym = inttype->u.sym;
return INT;
}
goto id;
case 'h': case 'j': case 'k': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'x': case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
id:
if (limit - rcp < MAXLINE) {
cp = rcp - 1;
fillbuf();
rcp = ++cp;
}
assert(cp == rcp);
token = (char *)rcp - 1;
while (map[*rcp]&(DIGIT|LETTER))
rcp++;
token = stringn(token, (char *)rcp - token);
tsym = lookup(token, identifiers);
cp = rcp;
return ID;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
unsigned long n = 0;
if (limit - rcp < MAXLINE) {
cp = rcp - 1;
fillbuf();
rcp = ++cp;
}
assert(cp == rcp);
token = (char *)rcp - 1;
if (*token == '0' && (*rcp == 'x' || *rcp == 'X')) {
int d, overflow = 0;
while (*++rcp) {
if (map[*rcp]&DIGIT)
d = *rcp - '0';
else if (*rcp >= 'a' && *rcp <= 'f')
d = *rcp - 'a' + 10;
else if (*rcp >= 'A' && *rcp <= 'F')
d = *rcp - 'A' + 10;
else
break;
if (n&~(~0UL >> 4))
overflow = 1;
else
n = (n<<4) + d;
}
if ((char *)rcp - token <= 2)
error("invalid hexadecimal constant `%S'\n", token, (char *)rcp-token);
cp = rcp;
tsym = icon(n, overflow, 16);
} else if (*token == '0') {
int err = 0, overflow = 0;
for ( ; map[*rcp]&DIGIT; rcp++) {
if (*rcp == '8' || *rcp == '9')
err = 1;
if (n&~(~0UL >> 3))
overflow = 1;
else
n = (n<<3) + (*rcp - '0');
}
if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') {
cp = rcp;
tsym = fcon();
return FCON;
}
cp = rcp;
tsym = icon(n, overflow, 8);
if (err)
error("invalid octal constant `%S'\n", token, (char*)cp-token);
} else {
int overflow = 0;
for (n = *token - '0'; map[*rcp]&DIGIT; ) {
int d = *rcp++ - '0';
if (n > (ULONG_MAX - d)/10)
overflow = 1;
else
n = 10*n + d;
}
if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') {
cp = rcp;
tsym = fcon();
return FCON;
}
cp = rcp;
tsym = icon(n, overflow, 10);
}
return ICON;
}
case '.':
if (rcp[0] == '.' && rcp[1] == '.') {
cp += 2;
return ELLIPSIS;
}
if ((map[*rcp]&DIGIT) == 0)
return '.';
if (limit - rcp < MAXLINE) {
cp = rcp - 1;
fillbuf();
rcp = ++cp;
}
assert(cp == rcp);
cp = rcp - 1;
token = (char *)cp;
tsym = fcon();
return FCON;
case 'L':
if (*rcp == '\'') {
unsigned int *s = scon(*cp, wcput, wcbuf);
if (s - wcbuf > 2)
warning("excess characters in wide-character literal ignored\n");
tval.type = widechar;
tval.u.c.v.u = wcbuf[0];
tsym = &tval;
return ICON;
} else if (*rcp == '"') {
unsigned int *s = scon(*cp, wcput, wcbuf);
tval.type = array(widechar, s - wcbuf, 0);
tval.u.c.v.p = wcbuf;
tsym = &tval;
return SCON;
} else
goto id;
case '\'': {
char *s = scon(*--cp, cput, cbuf);
if (s - cbuf > 2)
warning("excess characters in multibyte character literal ignored\n");
tval.type = inttype;
if (chartype->op == INT)
tval.u.c.v.i = extend(cbuf[0], chartype);
else
tval.u.c.v.i = cbuf[0]&0xFF;
tsym = &tval;
return ICON;
}
case '"': {
char *s = scon(*--cp, cput, cbuf);
tval.type = array(chartype, s - cbuf, 0);
tval.u.c.v.p = cbuf;
tsym = &tval;
return SCON;
}
case 'a':
if (rcp[0] == 'u'
&& rcp[1] == 't'
&& rcp[2] == 'o'
&& !(map[rcp[3]]&(DIGIT|LETTER))) {
cp = rcp + 3;
return AUTO;
}
goto id;
case 'b':
if (rcp[0] == 'r'
&& rcp[1] == 'e'
&& rcp[2] == 'a'
&& rcp[3] == 'k'
&& !(map[rcp[4]]&(DIGIT|LETTER))) {
cp = rcp + 4;
return BREAK;
}
goto id;
case 'c':
if (rcp[0] == 'a'
&& rcp[1] == 's'
&& rcp[2] == 'e'
&& !(map[rcp[3]]&(DIGIT|LETTER))) {
cp = rcp + 3;
return CASE;
}
if (rcp[0] == 'h'
&& rcp[1] == 'a'
&& rcp[2] == 'r'
&& !(map[rcp[3]]&(DIGIT|LETTER))) {
cp = rcp + 3;
tsym = chartype->u.sym;
return CHAR;
}
if (rcp[0] == 'o'
&& rcp[1] == 'n'
&& rcp[2] == 's'
&& rcp[3] == 't'
&& !(map[rcp[4]]&(DIGIT|LETTER))) {
cp = rcp + 4;
return CONST;
}
if (rcp[0] == 'o'
&& rcp[1] == 'n'
&& rcp[2] == 't'
&& rcp[3] == 'i'
&& rcp[4] == 'n'
&& rcp[5] == 'u'
&& rcp[6] == 'e'
&& !(map[rcp[7]]&(DIGIT|LETTER))) {
cp = rcp + 7;
return CONTINUE;
}
goto id;
case 'd':
if (rcp[0] == 'e'
&& rcp[1] == 'f'
&& rcp[2] == 'a'
&& rcp[3] == 'u'
&& rcp[4] == 'l'
&& rcp[5] == 't'
&& !(map[rcp[6]]&(DIGIT|LETTER))) {
cp = rcp + 6;
return DEFAULT;
}
if (rcp[0] == 'o'
&& rcp[1] == 'u'
&& rcp[2] == 'b'
&& rcp[3] == 'l'
&& rcp[4] == 'e'
&& !(map[rcp[5]]&(DIGIT|LETTER))) {
cp = rcp + 5;
tsym = doubletype->u.sym;
return DOUBLE;
}
if (rcp[0] == 'o'
&& !(map[rcp[1]]&(DIGIT|LETTER))) {
cp = rcp + 1;
return DO;
}
goto id;
case 'e':
if (rcp[0] == 'l'
&& rcp[1] == 's'
&& rcp[2] == 'e'
&& !(map[rcp[3]]&(DIGIT|LETTER))) {
cp = rcp + 3;
return ELSE;
}
if (rcp[0] == 'n'
&& rcp[1] == 'u'
&& rcp[2] == 'm'
&& !(map[rcp[3]]&(DIGIT|LETTER))) {
cp = rcp + 3;
return ENUM;
}
if (rcp[0] == 'x'
&& rcp[1] == 't'
&& rcp[2] == 'e'
&& rcp[3] == 'r'
&& rcp[4] == 'n'
&& !(map[rcp[5]]&(DIGIT|LETTER))) {
cp = rcp + 5;
return EXTERN;
}
goto id;
case 'f':
if (rcp[0] == 'l'
&& rcp[1] == 'o'
&& rcp[2] == 'a'
&& rcp[3] == 't'
&& !(map[rcp[4]]&(DIGIT|LETTER))) {
cp = rcp + 4;
tsym = floattype->u.sym;
return FLOAT;
}
if (rcp[0] == 'o'
&& rcp[1] == 'r'
&& !(map[rcp[2]]&(DIGIT|LETTER))) {
cp = rcp + 2;
return FOR;
}
goto id;
case 'g':
if (rcp[0] == 'o'
&& rcp[1] == 't'
&& rcp[2] == 'o'
&& !(map[rcp[3]]&(DIGIT|LETTER))) {
cp = rcp + 3;
return GOTO;
}
goto id;
case 'l':
if (rcp[0] == 'o'
&& rcp[1] == 'n'
&& rcp[2] == 'g'
&& !(map[rcp[3]]&(DIGIT|LETTER))) {
cp = rcp + 3;
return LONG;
}
goto id;
case 'r':
if (rcp[0] == 'e'
&& rcp[1] == 'g'
&& rcp[2] == 'i'
&& rcp[3] == 's'
&& rcp[4] == 't'
&& rcp[5] == 'e'
&& rcp[6] == 'r'
&& !(map[rcp[7]]&(DIGIT|LETTER))) {
cp = rcp + 7;
return REGISTER;
}
if (rcp[0] == 'e'
&& rcp[1] == 't'
&& rcp[2] == 'u'
&& rcp[3] == 'r'
&& rcp[4] == 'n'
&& !(map[rcp[5]]&(DIGIT|LETTER))) {
cp = rcp + 5;
return RETURN;
}
goto id;
case 's':
if (rcp[0] == 'h'
&& rcp[1] == 'o'
&& rcp[2] == 'r'
&& rcp[3] == 't'
&& !(map[rcp[4]]&(DIGIT|LETTER))) {
cp = rcp + 4;
return SHORT;
}
if (rcp[0] == 'i'
&& rcp[1] == 'g'
&& rcp[2] == 'n'
&& rcp[3] == 'e'
&& rcp[4] == 'd'
&& !(map[rcp[5]]&(DIGIT|LETTER))) {
cp = rcp + 5;
return SIGNED;
}
if (rcp[0] == 'i'
&& rcp[1] == 'z'
&& rcp[2] == 'e'
&& rcp[3] == 'o'
&& rcp[4] == 'f'
&& !(map[rcp[5]]&(DIGIT|LETTER))) {
cp = rcp + 5;
return SIZEOF;
}
if (rcp[0] == 't'
&& rcp[1] == 'a'
&& rcp[2] == 't'
&& rcp[3] == 'i'
&& rcp[4] == 'c'
&& !(map[rcp[5]]&(DIGIT|LETTER))) {
cp = rcp + 5;
return STATIC;
}
if (rcp[0] == 't'
&& rcp[1] == 'r'
&& rcp[2] == 'u'
&& rcp[3] == 'c'
&& rcp[4] == 't'
&& !(map[rcp[5]]&(DIGIT|LETTER))) {
cp = rcp + 5;
return STRUCT;
}
if (rcp[0] == 'w'
&& rcp[1] == 'i'
&& rcp[2] == 't'
&& rcp[3] == 'c'
&& rcp[4] == 'h'
&& !(map[rcp[5]]&(DIGIT|LETTER))) {
cp = rcp + 5;
return SWITCH;
}
goto id;
case 't':
if (rcp[0] == 'y'
&& rcp[1] == 'p'
&& rcp[2] == 'e'
&& rcp[3] == 'd'
&& rcp[4] == 'e'
&& rcp[5] == 'f'
&& !(map[rcp[6]]&(DIGIT|LETTER))) {
cp = rcp + 6;
return TYPEDEF;
}
goto id;
case 'u':
if (rcp[0] == 'n'
&& rcp[1] == 'i'
&& rcp[2] == 'o'
&& rcp[3] == 'n'
&& !(map[rcp[4]]&(DIGIT|LETTER))) {
cp = rcp + 4;
return UNION;
}
if (rcp[0] == 'n'
&& rcp[1] == 's'
&& rcp[2] == 'i'
&& rcp[3] == 'g'
&& rcp[4] == 'n'
&& rcp[5] == 'e'
&& rcp[6] == 'd'
&& !(map[rcp[7]]&(DIGIT|LETTER))) {
cp = rcp + 7;
return UNSIGNED;
}
goto id;
case 'v':
if (rcp[0] == 'o'
&& rcp[1] == 'i'
&& rcp[2] == 'd'
&& !(map[rcp[3]]&(DIGIT|LETTER))) {
cp = rcp + 3;
tsym = voidtype->u.sym;
return VOID;
}
if (rcp[0] == 'o'
&& rcp[1] == 'l'
&& rcp[2] == 'a'
&& rcp[3] == 't'
&& rcp[4] == 'i'
&& rcp[5] == 'l'
&& rcp[6] == 'e'
&& !(map[rcp[7]]&(DIGIT|LETTER))) {
cp = rcp + 7;
return VOLATILE;
}
goto id;
case 'w':
if (rcp[0] == 'h'
&& rcp[1] == 'i'
&& rcp[2] == 'l'
&& rcp[3] == 'e'
&& !(map[rcp[4]]&(DIGIT|LETTER))) {
cp = rcp + 4;
return WHILE;
}
goto id;
case '_':
if (rcp[0] == '_'
&& rcp[1] == 't'
&& rcp[2] == 'y'
&& rcp[3] == 'p'
&& rcp[4] == 'e'
&& rcp[5] == 'c'
&& rcp[6] == 'o'
&& rcp[7] == 'd'
&& rcp[8] == 'e'
&& !(map[rcp[9]]&(DIGIT|LETTER))) {
cp = rcp + 9;
return TYPECODE;
}
if (rcp[0] == '_'
&& rcp[1] == 'f'
&& rcp[2] == 'i'
&& rcp[3] == 'r'
&& rcp[4] == 's'
&& rcp[5] == 't'
&& rcp[6] == 'a'
&& rcp[7] == 'r'
&& rcp[8] == 'g'
&& !(map[rcp[9]]&(DIGIT|LETTER))) {
cp = rcp + 9;
return FIRSTARG;
}
goto id;
default:
if ((map[cp[-1]]&BLANK) == 0) {
if (cp[-1] < ' ' || cp[-1] >= 0177)
error("illegal character `\\0%o'\n", cp[-1]);
else
error("illegal character `%c'\n", cp[-1]);
}
}
}
}
static Symbol icon(unsigned long n, int overflow, int base) {
if (((*cp=='u'||*cp=='U') && (cp[1]=='l'||cp[1]=='L'))
|| ((*cp=='l'||*cp=='L') && (cp[1]=='u'||cp[1]=='U'))) {
tval.type = unsignedlong;
cp += 2;
} else if (*cp == 'u' || *cp == 'U') {
if (overflow || n > unsignedtype->u.sym->u.limits.max.i)
tval.type = unsignedlong;
else
tval.type = unsignedtype;
cp += 1;
} else if (*cp == 'l' || *cp == 'L') {
if (overflow || n > longtype->u.sym->u.limits.max.i)
tval.type = unsignedlong;
else
tval.type = longtype;
cp += 1;
} else if (overflow || n > longtype->u.sym->u.limits.max.i)
tval.type = unsignedlong;
else if (n > inttype->u.sym->u.limits.max.i)
tval.type = longtype;
else if (base != 10 && n > inttype->u.sym->u.limits.max.i)
tval.type = unsignedtype;
else
tval.type = inttype;
switch (tval.type->op) {
case INT:
if (overflow || n > tval.type->u.sym->u.limits.max.i) {
warning("overflow in constant `%S'\n", token,
(char*)cp - token);
tval.u.c.v.i = tval.type->u.sym->u.limits.max.i;
} else
tval.u.c.v.i = n;
break;
case UNSIGNED:
if (overflow || n > tval.type->u.sym->u.limits.max.u) {
warning("overflow in constant `%S'\n", token,
(char*)cp - token);
tval.u.c.v.u = tval.type->u.sym->u.limits.max.u;
} else
tval.u.c.v.u = n;
break;
default: assert(0);
}
ppnumber("integer");
return &tval;
}
static void ppnumber(char *which) {
unsigned char *rcp = cp--;
for ( ; (map[*cp]&(DIGIT|LETTER)) || *cp == '.'; cp++)
if ((cp[0] == 'E' || cp[0] == 'e')
&& (cp[1] == '-' || cp[1] == '+'))
cp++;
if (cp > rcp)
error("`%S' is a preprocessing number but an invalid %s constant\n", token,
(char*)cp-token, which);
}
static Symbol fcon(void) {
if (*cp == '.')
do
cp++;
while (map[*cp]&DIGIT);
if (*cp == 'e' || *cp == 'E') {
if (*++cp == '-' || *cp == '+')
cp++;
if (map[*cp]&DIGIT)
do
cp++;
while (map[*cp]&DIGIT);
else
error("invalid floating constant `%S'\n", token,
(char*)cp - token);
}
errno = 0;
tval.u.c.v.d = strtod(token, NULL);
if (errno == ERANGE)
warning("overflow in floating constant `%S'\n", token,
(char*)cp - token);
if (*cp == 'f' || *cp == 'F') {
++cp;
if (tval.u.c.v.d > floattype->u.sym->u.limits.max.d)
warning("overflow in floating constant `%S'\n", token,
(char*)cp - token);
tval.type = floattype;
} else if (*cp == 'l' || *cp == 'L') {
cp++;
tval.type = longdouble;
} else {
if (tval.u.c.v.d > doubletype->u.sym->u.limits.max.d)
warning("overflow in floating constant `%S'\n", token,
(char*)cp - token);
tval.type = doubletype;
}
ppnumber("floating");
return &tval;
}
static void *cput(int c, void *cl) {
char *s = cl;
if (c < 0 || c > 255)
warning("overflow in escape sequence with resulting value `%d'\n", c);
*s++ = c;
return s;
}
static void *wcput(int c, void *cl) {
unsigned int *s = cl;
*s++ = c;
return s;
}
static void *scon(int q, void *put(int c, void *cl), void *cl) {
int n = 0, nbad = 0;
do {
cp++;
while (*cp != q) {
int c;
if (map[*cp]&NEWLINE) {
if (cp < limit)
break;
cp++;
nextline();
if (cp == limit)
break;
continue;
}
c = *cp++;
if (c == '\\') {
if (map[*cp]&NEWLINE) {
if (cp < limit)
break;
cp++;
nextline();
}
if (limit - cp < MAXTOKEN)
fillbuf();
c = backslash(q);
} else if (c < 0 || c > 255 || map[c] == 0)
nbad++;
if (n++ < BUFSIZE)
cl = put(c, cl);
}
if (*cp == q)
cp++;
else
error("missing %c\n", q);
} while (q == '"' && getchr() == '"');
cl = put(0, cl);
if (n >= BUFSIZE)
error("%s literal too long\n", q == '"' ? "string" : "character");
if (Aflag >= 2 && q == '"' && n > 509)
warning("more than 509 characters in a string literal\n");
if (Aflag >= 2 && nbad > 0)
warning("%s literal contains non-portable characters\n",
q == '"' ? "string" : "character");
return cl;
}
int getchr(void) {
for (;;) {
while (map[*cp]&BLANK)
cp++;
if (!(map[*cp]&NEWLINE))
return *cp;
cp++;
nextline();
if (cp == limit)
return EOI;
}
}
static int backslash(int q) {
unsigned int c;
switch (*cp++) {
case 'a': return 7;
case 'b': return '\b';
case 'f': return '\f';
case 'n': return '\n';
case 'r': return '\r';
case 't': return '\t';
case 'v': return '\v';
case '\'': case '"': case '\\': case '\?': break;
case 'x': {
int overflow = 0;
if ((map[*cp]&(DIGIT|HEX)) == 0) {
if (*cp < ' ' || *cp == 0177)
error("ill-formed hexadecimal escape sequence\n");
else
error("ill-formed hexadecimal escape sequence `\\x%c'\n", *cp);
if (*cp != q)
cp++;
return 0;
}
for (c = 0; map[*cp]&(DIGIT|HEX); cp++) {
if (c >> (8*widechar->size - 4))
overflow = 1;
if (map[*cp]&DIGIT)
c = (c<<4) + *cp - '0';
else
c = (c<<4) + (*cp&~040) - 'A' + 10;
}
if (overflow)
warning("overflow in hexadecimal escape sequence\n");
return c&ones(8*widechar->size);
}
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
c = *(cp-1) - '0';
if (*cp >= '0' && *cp <= '7') {
c = (c<<3) + *cp++ - '0';
if (*cp >= '0' && *cp <= '7')
c = (c<<3) + *cp++ - '0';
}
return c;
default:
if (cp[-1] < ' ' || cp[-1] >= 0177)
warning("unrecognized character escape sequence\n");
else
warning("unrecognized character escape sequence `\\%c'\n", cp[-1]);
}
return cp[-1];
}

View File

@@ -1,56 +0,0 @@
#include "c.h"
static List freenodes; /* free list nodes */
/* append - append x to list, return new list */
List append(void *x, List list) {
List new;
if ((new = freenodes) != NULL)
freenodes = freenodes->link;
else
NEW(new, PERM);
if (list) {
new->link = list->link;
list->link = new;
} else
new->link = new;
new->x = x;
return new;
}
/* length - # elements in list */
int length(List list) {
int n = 0;
if (list) {
List lp = list;
do
n++;
while ((lp = lp->link) != list);
}
return n;
}
/* ltov - convert list to a NULL-terminated vector allocated in arena */
void *ltov(List *list, unsigned arena) {
int i = 0;
void **array = newarray(length(*list) + 1, sizeof array[0], arena);
if (*list) {
List lp = *list;
do {
lp = lp->link;
array[i++] = lp->x;
} while (lp != *list);
#ifndef PURIFY
lp = (*list)->link;
(*list)->link = freenodes;
freenodes = lp;
#endif
}
*list = NULL;
array[i] = NULL;
return array;
}

View File

@@ -1,225 +0,0 @@
#include "c.h"
static char rcsid[] = "main.c - faked rcsid";
static void typestab(Symbol, void *);
static void stabline(Coordinate *);
static void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *);
Interface *IR = NULL;
int Aflag; /* >= 0 if -A specified */
int Pflag; /* != 0 if -P specified */
int glevel; /* == [0-9] if -g[0-9] specified */
int xref; /* != 0 for cross-reference data */
Symbol YYnull; /* _YYnull symbol if -n or -nvalidate specified */
Symbol YYcheck; /* _YYcheck symbol if -nvalidate,check specified */
static char *comment;
static Interface stabIR;
static char *currentfile; /* current file name */
static int currentline; /* current line number */
static FILE *srcfp; /* stream for current file, if non-NULL */
static int srcpos; /* position of srcfp, if srcfp is non-NULL */
int main(int argc, char *argv[]) {
int i, j;
for (i = argc - 1; i > 0; i--)
if (strncmp(argv[i], "-target=", 8) == 0)
break;
if (i > 0) {
char *s = strchr(argv[i], '\\');
if (s != NULL)
*s = '/';
for (j = 0; bindings[j].name && bindings[j].ir; j++)
if (strcmp(&argv[i][8], bindings[j].name) == 0) {
IR = bindings[j].ir;
break;
}
if (s != NULL)
*s = '\\';
}
if (!IR) {
fprint(stderr, "%s: unknown target", argv[0]);
if (i > 0)
fprint(stderr, " `%s'", &argv[i][8]);
fprint(stderr, "; must specify one of\n");
for (i = 0; bindings[i].name; i++)
fprint(stderr, "\t-target=%s\n", bindings[i].name);
exit(EXIT_FAILURE);
}
init(argc, argv);
t = gettok();
(*IR->progbeg)(argc, argv);
if (glevel && IR->stabinit)
(*IR->stabinit)(firstfile, argc, argv);
program();
if (events.end)
apply(events.end, NULL, NULL);
memset(&events, 0, sizeof events);
if (glevel || xref) {
Symbol symroot = NULL;
Coordinate src;
foreach(types, GLOBAL, typestab, &symroot);
foreach(identifiers, GLOBAL, typestab, &symroot);
src.file = firstfile;
src.x = 0;
src.y = lineno;
if ((glevel > 2 || xref) && IR->stabend)
(*IR->stabend)(&src, symroot,
ltov(&loci, PERM),
ltov(&symbols, PERM), NULL);
else if (IR->stabend)
(*IR->stabend)(&src, NULL, NULL, NULL, NULL);
}
finalize();
(*IR->progend)();
deallocate(PERM);
return errcnt > 0;
}
/* main_init - process program arguments */
void main_init(int argc, char *argv[]) {
char *infile = NULL, *outfile = NULL;
int i;
static int inited;
if (inited)
return;
inited = 1;
type_init(argc, argv);
for (i = 1; i < argc; i++)
if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "-g2") == 0)
glevel = 2;
else if (strncmp(argv[i], "-g", 2) == 0) { /* -gn[,x] */
char *p = strchr(argv[i], ',');
glevel = atoi(argv[i]+2);
if (p) {
comment = p + 1;
if (glevel == 0)
glevel = 1;
if (stabIR.stabline == NULL) {
stabIR.stabline = IR->stabline;
stabIR.stabend = IR->stabend;
IR->stabline = stabline;
IR->stabend = stabend;
}
}
} else if (strcmp(argv[i], "-x") == 0)
xref++;
else if (strcmp(argv[i], "-A") == 0) {
++Aflag;
} else if (strcmp(argv[i], "-P") == 0)
Pflag++;
else if (strcmp(argv[i], "-w") == 0)
wflag++;
else if (strcmp(argv[i], "-n") == 0) {
if (!YYnull) {
YYnull = install(string("_YYnull"), &globals, GLOBAL, PERM);
YYnull->type = func(voidptype, NULL, 1);
YYnull->sclass = EXTERN;
(*IR->defsymbol)(YYnull);
}
} else if (strncmp(argv[i], "-n", 2) == 0) { /* -nvalid[,check] */
char *p = strchr(argv[i], ',');
if (p) {
YYcheck = install(string(p+1), &globals, GLOBAL, PERM);
YYcheck->type = func(voidptype, NULL, 1);
YYcheck->sclass = EXTERN;
(*IR->defsymbol)(YYcheck);
p = stringn(argv[i]+2, p - (argv[i]+2));
} else
p = string(argv[i]+2);
YYnull = install(p, &globals, GLOBAL, PERM);
YYnull->type = func(voidptype, NULL, 1);
YYnull->sclass = EXTERN;
(*IR->defsymbol)(YYnull);
} else if (strcmp(argv[i], "-v") == 0)
fprint(stderr, "%s %s\n", argv[0], rcsid);
else if (strncmp(argv[i], "-s", 2) == 0)
density = strtod(&argv[i][2], NULL);
else if (strncmp(argv[i], "-errout=", 8) == 0) {
FILE *f = fopen(argv[i]+8, "w");
if (f == NULL) {
fprint(stderr, "%s: can't write errors to `%s'\n", argv[0], argv[i]+8);
exit(EXIT_FAILURE);
}
fclose(f);
f = freopen(argv[i]+8, "w", stderr);
assert(f);
} else if (strncmp(argv[i], "-e", 2) == 0) {
int x;
if ((x = strtol(&argv[i][2], NULL, 0)) > 0)
errlimit = x;
} else if (strncmp(argv[i], "-little_endian=", 15) == 0)
IR->little_endian = argv[i][15] - '0';
else if (strncmp(argv[i], "-mulops_calls=", 18) == 0)
IR->mulops_calls = argv[i][18] - '0';
else if (strncmp(argv[i], "-wants_callb=", 13) == 0)
IR->wants_callb = argv[i][13] - '0';
else if (strncmp(argv[i], "-wants_argb=", 12) == 0)
IR->wants_argb = argv[i][12] - '0';
else if (strncmp(argv[i], "-left_to_right=", 15) == 0)
IR->left_to_right = argv[i][15] - '0';
else if (strncmp(argv[i], "-wants_dag=", 11) == 0)
IR->wants_dag = argv[i][11] - '0';
else if (*argv[i] != '-' || strcmp(argv[i], "-") == 0) {
if (infile == NULL)
infile = argv[i];
else if (outfile == NULL)
outfile = argv[i];
}
if (infile != NULL && strcmp(infile, "-") != 0
&& freopen(infile, "r", stdin) == NULL) {
fprint(stderr, "%s: can't read `%s'\n", argv[0], infile);
exit(EXIT_FAILURE);
}
if (outfile != NULL && strcmp(outfile, "-") != 0
&& freopen(outfile, "w", stdout) == NULL) {
fprint(stderr, "%s: can't write `%s'\n", argv[0], outfile);
exit(EXIT_FAILURE);
}
}
/* typestab - emit stab entries for p */
static void typestab(Symbol p, void *cl) {
if (*(Symbol *)cl == 0 && p->sclass && p->sclass != TYPEDEF)
*(Symbol *)cl = p;
if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype)
(*IR->stabtype)(p);
}
/* stabline - emit source code for source coordinate *cp */
static void stabline(Coordinate *cp) {
if (cp->file && cp->file != currentfile) {
if (srcfp)
fclose(srcfp);
currentfile = cp->file;
srcfp = fopen(currentfile, "r");
srcpos = 0;
currentline = 0;
}
if (currentline != cp->y && srcfp) {
char buf[512];
if (srcpos > cp->y) {
rewind(srcfp);
srcpos = 0;
}
for ( ; srcpos < cp->y; srcpos++)
if (fgets(buf, sizeof buf, srcfp) == NULL) {
fclose(srcfp);
srcfp = NULL;
break;
}
if (srcfp && srcpos == cp->y)
print("%s%s", comment, buf);
}
currentline = cp->y;
if (stabIR.stabline)
(*stabIR.stabline)(cp);
}
static void stabend(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {
if (stabIR.stabend)
(*stabIR.stabend)(cp, p, cpp, sp, stab);
if (srcfp)
fclose(srcfp);
}

View File

@@ -1,74 +0,0 @@
#include "c.h"
#define I(f) null_##f
static Node I(gen)(Node p) { return p; }
static void I(address)(Symbol q, Symbol p, long n) {}
static void I(blockbeg)(Env *e) {}
static void I(blockend)(Env *e) {}
static void I(defaddress)(Symbol p) {}
static void I(defconst)(int suffix, int size, Value v) {}
static void I(defstring)(int len, char *s) {}
static void I(defsymbol)(Symbol p) {}
static void I(emit)(Node p) {}
static void I(export)(Symbol p) {}
static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {}
static void I(global)(Symbol p) {}
static void I(import)(Symbol p) {}
static void I(local)(Symbol p) {}
static void I(progbeg)(int argc, char *argv[]) {}
static void I(progend)(void) {}
static void I(segment)(int s) {}
static void I(space)(int n) {}
static void I(stabblock)(int brace, int lev, Symbol *p) {}
static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {}
static void I(stabfend)(Symbol p, int lineno) {}
static void I(stabinit)(char *file, int argc, char *argv[]) {}
static void I(stabline)(Coordinate *cp) {}
static void I(stabsym)(Symbol p) {}
static void I(stabtype)(Symbol p) {}
Interface nullIR = {
{1, 1, 0}, /* char */
{2, 2, 0}, /* short */
{4, 4, 0}, /* int */
{8, 8, 1}, /* long */
{8 ,8, 1}, /* long long */
{4, 4, 1}, /* float */
{8, 8, 1}, /* double */
{16,16,1}, /* long double */
{4, 4, 0}, /* T* */
{0, 4, 0}, /* struct */
1, /* little_endian */
0, /* mulops_calls */
0, /* wants_callb */
0, /* wants_argb */
1, /* left_to_right */
0, /* wants_dag */
0, /* unsigned_char */
I(address),
I(blockbeg),
I(blockend),
I(defaddress),
I(defconst),
I(defstring),
I(defsymbol),
I(emit),
I(export),
I(function),
I(gen),
I(global),
I(import),
I(local),
I(progbeg),
I(progend),
I(segment),
I(space),
I(stabblock),
I(stabend),
I(stabfend),
I(stabinit),
I(stabline),
I(stabsym),
I(stabtype)
};

View File

@@ -1,135 +0,0 @@
#include "c.h"
static char *outs(const char *str, FILE *f, char *bp) {
if (f)
fputs(str, f);
else
while ((*bp = *str++))
bp++;
return bp;
}
static char *outd(long n, FILE *f, char *bp) {
unsigned long m;
char buf[25], *s = buf + sizeof buf;
*--s = '\0';
if (n < 0)
m = -n;
else
m = n;
do
*--s = m%10 + '0';
while ((m /= 10) != 0);
if (n < 0)
*--s = '-';
return outs(s, f, bp);
}
static char *outu(unsigned long n, int base, FILE *f, char *bp) {
char buf[25], *s = buf + sizeof buf;
*--s = '\0';
do
*--s = "0123456789abcdef"[n%base];
while ((n /= base) != 0);
return outs(s, f, bp);
}
void print(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprint(stdout, NULL, fmt, ap);
va_end(ap);
}
/* fprint - formatted output to f */
void fprint(FILE *f, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprint(f, NULL, fmt, ap);
va_end(ap);
}
/* stringf - formatted output to a saved string */
char *stringf(const char *fmt, ...) {
char buf[1024];
va_list ap;
va_start(ap, fmt);
vfprint(NULL, buf, fmt, ap);
va_end(ap);
return string(buf);
}
/* vfprint - formatted output to f or string bp */
void vfprint(FILE *f, char *bp, const char *fmt, va_list ap) {
for (; *fmt; fmt++)
if (*fmt == '%')
switch (*++fmt) {
case 'd': bp = outd(va_arg(ap, int), f, bp); break;
case 'D': bp = outd(va_arg(ap, long), f, bp); break;
case 'U': bp = outu(va_arg(ap, unsigned long), 10, f, bp); break;
case 'u': bp = outu(va_arg(ap, unsigned), 10, f, bp); break;
case 'o': bp = outu(va_arg(ap, unsigned), 8, f, bp); break;
case 'X': bp = outu(va_arg(ap, unsigned long), 16, f, bp); break;
case 'x': bp = outu(va_arg(ap, unsigned), 16, f, bp); break;
case 'f': case 'e':
case 'g': {
static char format[] = "%f";
char buf[128];
format[1] = *fmt;
sprintf(buf, format, va_arg(ap, double));
bp = outs(buf, f, bp);
}
; break;
case 's': bp = outs(va_arg(ap, char *), f, bp); break;
case 'p': {
void *p = va_arg(ap, void *);
if (p)
bp = outs("0x", f, bp);
bp = outu((unsigned long)p, 16, f, bp);
break;
}
case 'c': if (f) fputc(va_arg(ap, int), f); else *bp++ = va_arg(ap, int); break;
case 'S': { char *s = va_arg(ap, char *);
int n = va_arg(ap, int);
if (s) {
for ( ; n-- > 0; s++)
if (f) (void)putc(*s, f); else *bp++ = *s;
}
} break;
case 'k': { int t = va_arg(ap, int);
static char *tokens[] = {
#define xx(a,b,c,d,e,f,g) g,
#define yy(a,b,c,d,e,f,g) g,
#include "token.h"
};
assert(tokens[t&0177]);
bp = outs(tokens[t&0177], f, bp);
} break;
case 't': { Type ty = va_arg(ap, Type);
assert(f);
outtype(ty ? ty : voidtype, f);
} break;
case 'w': { Coordinate *p = va_arg(ap, Coordinate *);
if (p->file && *p->file) {
bp = outs(p->file, f, bp);
bp = outs(":", f, bp);
}
bp = outd(p->y, f, bp);
} break;
case 'I': { int n = va_arg(ap, int);
while (--n >= 0)
if (f) (void)putc(' ', f); else *bp++ = ' ';
} break;
default: if (f) (void)putc(*fmt, f); else *bp++ = *fmt; break;
}
else if (f)
(void)putc(*fmt, f);
else
*bp++ = *fmt;
if (!f)
*bp = '\0';
}

View File

@@ -1,228 +0,0 @@
#include "c.h"
struct callsite {
char *file, *name;
union coordinate {
unsigned int coord;
struct { unsigned int y:16,x:10,index:6; } le;
struct { unsigned int index:6,x:10,y:16; } be;
} u;
};
struct func {
struct func *link;
struct caller *callers;
char *name;
union coordinate src;
};
struct map { /* source code map; 200 coordinates/map */
int size;
union coordinate u[200];
};
int npoints; /* # of execution points if -b specified */
int ncalled = -1; /* #times prof.out says current function was called */
static Symbol YYlink; /* symbol for file's struct _bbdata */
static Symbol YYcounts; /* symbol for _YYcounts if -b specified */
static List maplist; /* list of struct map *'s */
static List filelist; /* list of file names */
static Symbol funclist; /* list of struct func *'s */
static Symbol afunc; /* current function's struct func */
/* bbcall - build tree to set _callsite at call site *cp, emit call site data */
static void bbcall(Symbol yycounts, Coordinate *cp, Tree *e) {
static Symbol caller;
Value v;
union coordinate u;
Symbol p = genident(STATIC, array(voidptype, 0, 0), GLOBAL);
Tree t = *e;
defglobal(p, LIT);
defpointer(cp->file ? mkstr(cp->file)->u.c.loc : (Symbol)0);
defpointer(mkstr(cfunc->name)->u.c.loc);
if (IR->little_endian) {
u.le.x = cp->x;
u.le.y = cp->y;
} else {
u.be.x = cp->x;
u.be.y = cp->y;
}
(*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v));
if (caller == 0) {
caller = mksymbol(EXTERN, "_caller", ptr(voidptype));
caller->defined = 0;
}
if (generic((*e)->op) != CALL)
t = (*e)->kids[0];
assert(generic(t->op) == CALL);
t = tree(t->op, t->type,
tree(RIGHT, t->kids[0]->type,
t->kids[0],
tree(RIGHT, t->kids[0]->type, asgn(caller, idtree(p)), t->kids[0])),
t->kids[1]);
if (generic((*e)->op) != CALL)
t = tree((*e)->op, (*e)->type, t, (*e)->kids[1]);
*e = t;
}
/* bbentry - return tree for _prologue(&afunc, &YYlink)' */
static void bbentry(Symbol yylink, Symbol f) {
static Symbol prologue;
afunc = genident(STATIC, array(voidptype, 4, 0), GLOBAL);
if (prologue == 0) {
prologue = mksymbol(EXTERN, "_prologue", ftype(inttype, voidptype));
prologue->defined = 0;
}
walk(vcall(prologue, voidtype, pointer(idtree(afunc)), pointer(idtree(yylink)), NULL), 0, 0);
}
/* bbexit - return tree for _epilogue(&afunc)' */
static void bbexit(Symbol yylink, Symbol f, Tree e) {
static Symbol epilogue;
if (epilogue == 0) {
epilogue = mksymbol(EXTERN, "_epilogue", ftype(inttype, voidptype));
epilogue->defined = 0;
}
walk(vcall(epilogue, voidtype, pointer(idtree(afunc)), NULL), 0, 0);
}
/* bbfile - add file to list of file names, return its index */
static int bbfile(char *file) {
if (file) {
List lp;
int i = 1;
if ((lp = filelist) != NULL)
do {
lp = lp->link;
if (((Symbol)lp->x)->u.c.v.p == file)
return i;
i++;
} while (lp != filelist);
filelist = append(mkstr(file), filelist);
return i;
}
return 0;
}
/* bbfunc - emit function name and src coordinates */
static void bbfunc(Symbol yylink, Symbol f) {
Value v;
union coordinate u;
defglobal(afunc, DATA);
defpointer(funclist);
defpointer(NULL);
defpointer(mkstr(f->name)->u.c.loc);
if (IR->little_endian) {
u.le.x = f->u.f.pt.x;
u.le.y = f->u.f.pt.y;
u.le.index = bbfile(f->u.f.pt.file);
} else {
u.be.x = f->u.f.pt.x;
u.be.y = f->u.f.pt.y;
u.be.index = bbfile(f->u.f.pt.file);
}
(*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v));
funclist = afunc;
}
/* bbincr - build tree to increment execution point at *cp */
static void bbincr(Symbol yycounts, Coordinate *cp, Tree *e) {
struct map *mp = maplist->x;
Tree t;
/* append *cp to source map */
if (mp->size >= NELEMS(mp->u)) {
NEW(mp, PERM);
mp->size = 0;
maplist = append(mp, maplist);
}
if (IR->little_endian) {
mp->u[mp->size].le.x = cp->x;
mp->u[mp->size].le.y = cp->y;
mp->u[mp->size++].le.index = bbfile(cp->file);
} else {
mp->u[mp->size].be.x = cp->x;
mp->u[mp->size].be.y = cp->y;
mp->u[mp->size++].be.index = bbfile(cp->file);
}
t = incr('+', rvalue((*optree['+'])(ADD, pointer(idtree(yycounts)),
consttree(npoints++, inttype))), consttree(1, inttype));
if (*e)
*e = tree(RIGHT, (*e)->type, t, *e);
else
*e = t;
}
/* bbvars - emit definition for basic block counting data */
static void bbvars(Symbol yylink) {
int i, j, n = npoints;
Value v;
struct map **mp;
Symbol coords, files, *p;
if (!YYcounts && !yylink)
return;
if (YYcounts) {
if (n <= 0)
n = 1;
YYcounts->type = array(unsignedtype, n, 0);
defglobal(YYcounts, BSS);
}
files = genident(STATIC, array(charptype, 1, 0), GLOBAL);
defglobal(files, LIT);
for (p = ltov(&filelist, PERM); *p; p++)
defpointer((*p)->u.c.loc);
defpointer(NULL);
coords = genident(STATIC, array(unsignedtype, n, 0), GLOBAL);
defglobal(coords, LIT);
for (i = n, mp = ltov(&maplist, PERM); *mp; i -= (*mp)->size, mp++)
for (j = 0; j < (*mp)->size; j++)
(*IR->defconst)(U, unsignedtype->size, (v.u = (*mp)->u[j].coord, v));
if (i > 0)
(*IR->space)(i*coords->type->type->size);
defpointer(NULL);
defglobal(yylink, DATA);
defpointer(NULL);
(*IR->defconst)(U, unsignedtype->size, (v.u = n, v));
defpointer(YYcounts);
defpointer(coords);
defpointer(files);
defpointer(funclist);
}
/* profInit - initialize basic block profiling options */
void prof_init(int argc, char *argv[]) {
int i;
static int inited;
if (inited)
return;
inited = 1;
type_init(argc, argv);
if (IR) {
for (i = 1; i < argc; i++)
if (strncmp(argv[i], "-a", 2) == 0) {
if (ncalled == -1
&& process(argv[i][2] ? &argv[i][2] : "prof.out") > 0)
ncalled = 0;
} else if ((strcmp(argv[i], "-b") == 0
|| strcmp(argv[i], "-C") == 0) && YYlink == 0) {
YYlink = genident(STATIC, array(unsignedtype, 0, 0), GLOBAL);
attach((Apply)bbentry, YYlink, &events.entry);
attach((Apply)bbexit, YYlink, &events.returns);
attach((Apply)bbfunc, YYlink, &events.exit);
attach((Apply)bbvars, YYlink, &events.end);
if (strcmp(argv[i], "-b") == 0) {
YYcounts = genident(STATIC, array(unsignedtype, 0, 0), GLOBAL);
maplist = append(allocate(sizeof (struct map), PERM), maplist);
((struct map *)maplist->x)->size = 0;
attach((Apply)bbcall, YYcounts, &events.calls);
attach((Apply)bbincr, YYcounts, &events.points);
}
}
}
}

View File

@@ -1,276 +0,0 @@
/* C compiler: prof.out input
prof.out format:
#files
name
... (#files-1 times)
#functions
name file# x y count caller file x y
... (#functions-1 times)
#points
file# x y count
... (#points-1 times)
*/
#include "c.h"
struct count { /* count data: */
int x, y; /* source coordinate */
int count; /* associated execution count */
};
#define MAXTOKEN 64
struct file { /* per-file prof.out data: */
struct file *link; /* link to next file */
char *name; /* file name */
int size; /* size of counts[] */
int count; /* counts[0..count-1] hold valid data */
struct count *counts; /* count data */
struct func { /* function data: */
struct func *link; /* link to next function */
char *name; /* function name */
struct count count; /* total number of calls */
struct caller { /* caller data: */
struct caller *link; /* link to next caller */
char *name; /* caller's name */
char *file; /* call site: file, x, y */
int x, y;
int count; /* number of calls from this site */
} *callers;
} *funcs; /* list of functions */
} *filelist;
FILE *fp;
/* acaller - add caller and site (file,x,y) to callee's callers list */
static void acaller(char *caller, char *file, int x, int y, int count, struct func *callee) {
struct caller *q;
assert(callee);
for (q = callee->callers; q && (caller != q->name
|| file != q->file || x != q->x || y != q->y); q = q->link)
;
if (!q) {
struct caller **r;
NEW(q, PERM);
q->name = caller;
q->file = file;
q->x = x;
q->y = y;
q->count = 0;
for (r = &callee->callers; *r && (strcmp(q->name, (*r)->name) > 0
|| strcmp(q->file, (*r)->file) > 0 || q->y > (*r)->y || q->y > (*r)->y); r = &(*r)->link)
;
q->link = *r;
*r = q;
}
q->count += count;
}
/* compare - return <0, 0, >0 if a<b, a==b, a>b, resp. */
static int compare(struct count *a, struct count *b) {
if (a->y == b->y)
return a->x - b->x;
return a->y - b->y;
}
/* findfile - return file name's file list entry, or 0 */
static struct file *findfile(char *name) {
struct file *p;
for (p = filelist; p; p = p->link)
if (p->name == name)
return p;
return 0;
}
/* afunction - add function name and its data to file's function list */
static struct func *afunction(char *name, char *file, int x, int y, int count) {
struct file *p = findfile(file);
struct func *q;
assert(p);
for (q = p->funcs; q && name != q->name; q = q->link)
;
if (!q) {
struct func **r;
NEW(q, PERM);
q->name = name;
q->count.x = x;
q->count.y = y;
q->count.count = 0;
q->callers = 0;
for (r = &p->funcs; *r && compare(&q->count, &(*r)->count) > 0; r = &(*r)->link)
;
q->link = *r;
*r = q;
}
q->count.count += count;
return q;
}
/* apoint - append execution point i to file's data */
static void apoint(int i, char *file, int x, int y, int count) {
struct file *p = findfile(file);
assert(p);
if (i >= p->size) {
int j;
if (p->size == 0) {
p->size = i >= 200 ? 2*i : 200;
p->counts = newarray(p->size, sizeof *p->counts, PERM);
} else {
struct count *new;
p->size = 2*i;
new = newarray(p->size, sizeof *new, PERM);
for (j = 0; j < p->count; j++)
new[j] = p->counts[j];
p->counts = new;
}
for (j = p->count; j < p->size; j++) {
static struct count z;
p->counts[j] = z;
}
}
p->counts[i].x = x;
p->counts[i].y = y;
p->counts[i].count += count;
if (i >= p->count)
p->count = i + 1;
}
/* findcount - return count associated with (file,x,y) or -1 */
int findcount(char *file, int x, int y) {
static struct file *cursor;
if (cursor == 0 || cursor->name != file)
cursor = findfile(file);
if (cursor) {
int l, u;
struct count *c = cursor->counts;
for (l = 0, u = cursor->count - 1; l <= u; ) {
int k = (l + u)/2;
if (c[k].y > y || (c[k].y == y && c[k].x > x))
u = k - 1;
else if (c[k].y < y || (c[k].y == y && c[k].x < x))
l = k + 1;
else
return c[k].count;
}
}
return -1;
}
/* findfunc - return count associated with function name in file or -1 */
int findfunc(char *name, char *file) {
static struct file *cursor;
if (cursor == 0 || cursor->name != file)
cursor = findfile(file);
if (cursor) {
struct func *p;
for (p = cursor->funcs; p; p = p->link)
if (p->name == name)
return p->count.count;
}
return -1;
}
/* getd - read a nonnegative number */
static int getd(void) {
int c, n = 0;
while ((c = getc(fp)) != EOF && (c == ' ' || c == '\n' || c == '\t'))
;
if (c >= '0' && c <= '9') {
do
n = 10*n + (c - '0');
while ((c = getc(fp)) >= '0' && c <= '9');
return n;
}
return -1;
}
/* getstr - read a string */
static char *getstr(void) {
int c;
char buf[MAXTOKEN], *s = buf;
while ((c = getc(fp)) != EOF && c != ' ' && c != '\n' && c != '\t')
if (s - buf < (int)sizeof buf - 2)
*s++ = c;
*s = 0;
return s == buf ? (char *)0 : string(buf);
}
/* gather - read prof.out data from fd */
static int gather(void) {
int i, nfiles, nfuncs, npoints;
char *files[64];
if ((nfiles = getd()) < 0)
return 0;
assert(nfiles < NELEMS(files));
for (i = 0; i < nfiles; i++) {
if ((files[i] = getstr()) == 0)
return -1;
if (!findfile(files[i])) {
struct file *new;
NEW(new, PERM);
new->name = files[i];
new->size = new->count = 0;
new->counts = 0;
new->funcs = 0;
new->link = filelist;
filelist = new;
}
}
if ((nfuncs = getd()) < 0)
return -1;
for (i = 0; i < nfuncs; i++) {
struct func *q;
char *name, *file;
int f, x, y, count;
if ((name = getstr()) == 0 || (f = getd()) <= 0
|| (x = getd()) < 0 || (y = getd()) < 0 || (count = getd()) < 0)
return -1;
q = afunction(name, files[f-1], x, y, count);
if ((name = getstr()) == 0 || (file = getstr()) == 0
|| (x = getd()) < 0 || (y = getd()) < 0)
return -1;
if (*name != '?')
acaller(name, file, x, y, count, q);
}
if ((npoints = getd()) < 0)
return -1;
for (i = 0; i < npoints; i++) {
int f, x, y, count;
if ((f = getd()) < 0 || (x = getd()) < 0 || (y = getd()) < 0
|| (count = getd()) < 0)
return -1;
if (f)
apoint(i, files[f-1], x, y, count);
}
return 1;
}
/* process - read prof.out data from file */
int process(char *file) {
int more;
if ((fp = fopen(file, "r")) != NULL) {
struct file *p;
while ((more = gather()) > 0)
;
fclose(fp);
if (more < 0)
return more;
for (p = filelist; p; p = p->link)
qsort(p->counts, p->count, sizeof *p->counts,
(int (*)(const void *, const void *))
compare);
return 1;
}
return 0;
}

View File

@@ -1,587 +0,0 @@
#include "c.h"
#include <float.h>
#define foldcnst(TYPE,VAR,OP) \
if (l->op == CNST+TYPE && r->op == CNST+TYPE) \
return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR)
#define commute(L,R) \
if (generic(R->op) == CNST && generic(L->op) != CNST) \
do { Tree t = L; L = R; R = t; } while(0)
#define xfoldcnst(TYPE,VAR,OP,FUNC)\
if (l->op == CNST+TYPE && r->op == CNST+TYPE\
&& FUNC(l->u.v.VAR,r->u.v.VAR,\
ty->u.sym->u.limits.min.VAR,\
ty->u.sym->u.limits.max.VAR, needconst)) \
return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR)
#define xcvtcnst(FTYPE,SRC,DST,VAR,EXPR) \
if (l->op == CNST+FTYPE) do {\
if (!explicitCast\
&& ((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\
warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, DST);\
if (needconst\
|| !((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\
return cnsttree(ty, (EXPR)); } while(0)
#define identity(X,Y,TYPE,VAR,VAL) \
if (X->op == CNST+TYPE && X->u.v.VAR == VAL) return Y
#define zerofield(OP,TYPE,VAR) \
if (l->op == FIELD \
&& r->op == CNST+TYPE && r->u.v.VAR == 0)\
return eqtree(OP, bittree(BAND, l->kids[0],\
cnsttree(unsignedtype, \
(unsigned long)fieldmask(l->u.field)<<fieldright(l->u.field))), r)
#define cfoldcnst(TYPE,VAR,OP) \
if (l->op == CNST+TYPE && r->op == CNST+TYPE) \
return cnsttree(inttype, (long)(l->u.v.VAR OP r->u.v.VAR))
#define foldaddp(L,R,RTYPE,VAR) \
if (L->op == CNST+P && R->op == CNST+RTYPE) { \
Tree e = tree(CNST+P, ty, NULL, NULL);\
e->u.v.p = (char *)L->u.v.p + R->u.v.VAR;\
return e; }
#define ufoldcnst(TYPE,EXP) if (l->op == CNST+TYPE) return EXP
#define sfoldcnst(OP) \
if (l->op == CNST+U && r->op == CNST+I \
&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) \
return cnsttree(ty, (unsigned long)(l->u.v.u OP r->u.v.i))
#define geu(L,R,V) \
if (R->op == CNST+U && R->u.v.u == 0) do { \
warning("result of unsigned comparison is constant\n"); \
return tree(RIGHT, inttype, root(L), cnsttree(inttype, (long)(V))); } while(0)
#define idempotent(OP) if (l->op == OP) return l->kids[0]
int needconst;
int explicitCast;
static int addi(long x, long y, long min, long max, int needconst) {
int cond = x == 0 || y == 0
|| (x < 0 && y < 0 && x >= min - y)
|| (x < 0 && y > 0)
|| (x > 0 && y < 0)
|| (x > 0 && y > 0 && x <= max - y);
if (!cond && needconst) {
warning("overflow in constant expression\n");
cond = 1;
}
return cond;
}
static int addd(double x, double y, double min, double max, int needconst) {
int cond = x == 0 || y == 0
|| (x < 0 && y < 0 && x >= min - y)
|| (x < 0 && y > 0)
|| (x > 0 && y < 0)
|| (x > 0 && y > 0 && x <= max - y);
if (!cond && needconst) {
warning("overflow in constant expression\n");
cond = 1;
}
return cond;
}
static Tree addrtree(Tree e, long n, Type ty) {
Symbol p = e->u.sym, q;
if (p->scope == GLOBAL
|| p->sclass == STATIC || p->sclass == EXTERN)
NEW0(q, PERM);
else
NEW0(q, FUNC);
q->name = stringd(genlabel(1));
q->sclass = p->sclass;
q->scope = p->scope;
assert(isptr(ty) || isarray(ty));
q->type = isptr(ty) ? ty->type : ty;
q->temporary = p->temporary;
q->generated = p->generated;
q->addressed = p->addressed;
q->computed = 1;
q->defined = 1;
q->ref = 1;
if (p->scope == GLOBAL
|| p->sclass == STATIC || p->sclass == EXTERN) {
if (p->sclass == AUTO)
q->sclass = STATIC;
(*IR->address)(q, p, n);
} else {
Code cp;
addlocal(p);
cp = code(Address);
cp->u.addr.sym = q;
cp->u.addr.base = p;
cp->u.addr.offset = n;
}
e = tree(e->op, ty, NULL, NULL);
e->u.sym = q;
return e;
}
/* div[id] - return 1 if min <= x/y <= max, 0 otherwise */
static int divi(long x, long y, long min, long max, int needconst) {
int cond = y != 0 && !(x == min && y == -1);
if (!cond && needconst) {
warning("overflow in constant expression\n");
cond = 1;
}
return cond;
}
static int divd(double x, double y, double min, double max, int needconst) {
int cond;
if (x < 0) x = -x;
if (y < 0) y = -y;
cond = y != 0 && !(y < 1 && x > max*y);
if (!cond && needconst) {
warning("overflow in constant expression\n");
cond = 1;
}
return cond;
}
/* mul[id] - return 1 if min <= x*y <= max, 0 otherwise */
static int muli(long x, long y, long min, long max, int needconst) {
int cond = (x > -1 && x <= 1) || (y > -1 && y <= 1)
|| (x < 0 && y < 0 && -x <= max/-y)
|| (x < 0 && y > 0 && x >= min/y)
|| (x > 0 && y < 0 && y >= min/x)
|| (x > 0 && y > 0 && x <= max/y);
if (!cond && needconst) {
warning("overflow in constant expression\n");
cond = 1;
}
return cond;
}
static int muld(double x, double y, double min, double max, int needconst) {
int cond = (x >= -1 && x <= 1) || (y >= -1 && y <= 1)
|| (x < 0 && y < 0 && -x <= max/-y)
|| (x < 0 && y > 0 && x >= min/y)
|| (x > 0 && y < 0 && y >= min/x)
|| (x > 0 && y > 0 && x <= max/y);
if (!cond && needconst) {
warning("overflow in constant expression\n");
cond = 1;
}
return cond;
}
/* sub[id] - return 1 if min <= x-y <= max, 0 otherwise */
static int subi(long x, long y, long min, long max, int needconst) {
return addi(x, -y, min, max, needconst);
}
static int subd(double x, double y, double min, double max, int needconst) {
return addd(x, -y, min, max, needconst);
}
Tree constexpr(int tok) {
Tree p;
needconst++;
p = expr1(tok);
needconst--;
return p;
}
int intexpr(int tok, int n) {
Tree p = constexpr(tok);
needconst++;
if (p->op == CNST+I || p->op == CNST+U)
n = cast(p, inttype)->u.v.i;
else
error("integer expression must be constant\n");
needconst--;
return n;
}
Tree simplify(int op, Type ty, Tree l, Tree r) {
int n;
if (optype(op) == 0)
op = mkop(op, ty);
switch (op) {
case ADD+U:
foldcnst(U,u,+);
commute(r,l);
identity(r,l,U,u,0);
break;
case ADD+I:
xfoldcnst(I,i,+,addi);
commute(r,l);
identity(r,l,I,i,0);
break;
case CVI+I:
xcvtcnst(I,l->u.v.i,ty,i,(long)extend(l->u.v.i,ty));
break;
case CVU+I:
if (l->op == CNST+U) {
if (!explicitCast && l->u.v.u > ty->u.sym->u.limits.max.i)
warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, ty);
if (needconst || !(l->u.v.u > ty->u.sym->u.limits.max.i))
return cnsttree(ty, (long)extend(l->u.v.u,ty));
}
break;
case CVP+U:
xcvtcnst(P,(unsigned long)l->u.v.p,ty,u,(unsigned long)l->u.v.p);
break;
case CVU+P:
xcvtcnst(U,(void*)l->u.v.u,ty,p,(void*)l->u.v.u);
break;
case CVP+P:
xcvtcnst(P,l->u.v.p,ty,p,l->u.v.p);
break;
case CVI+U:
xcvtcnst(I,l->u.v.i,ty,u,((unsigned long)l->u.v.i)&ones(8*ty->size));
break;
case CVU+U:
xcvtcnst(U,l->u.v.u,ty,u,l->u.v.u&ones(8*ty->size));
break;
case CVI+F:
xcvtcnst(I,l->u.v.i,ty,d,(double)l->u.v.i);
case CVU+F:
xcvtcnst(U,l->u.v.u,ty,d,(double)l->u.v.u);
break;
case CVF+I:
xcvtcnst(F,l->u.v.d,ty,i,(long)l->u.v.d);
break;
case CVF+F: {
float d = 0.0f;
if (l->op == CNST+F) {
if (l->u.v.d < ty->u.sym->u.limits.min.d)
d = ty->u.sym->u.limits.min.d;
else if (l->u.v.d > ty->u.sym->u.limits.max.d)
d = ty->u.sym->u.limits.max.d;
else
d = l->u.v.d;
}
xcvtcnst(F,l->u.v.d,ty,d,(double)d);
break;
}
case BAND+U:
foldcnst(U,u,&);
commute(r,l);
identity(r,l,U,u,ones(8*ty->size));
if (r->op == CNST+U && r->u.v.u == 0)
return tree(RIGHT, ty, root(l), cnsttree(ty, 0UL));
break;
case BAND+I:
foldcnst(I,i,&);
commute(r,l);
identity(r,l,I,i,ones(8*ty->size));
if (r->op == CNST+I && r->u.v.u == 0)
return tree(RIGHT, ty, root(l), cnsttree(ty, 0L));
break;
case MUL+U:
commute(l,r);
if (l->op == CNST+U && (n = ispow2(l->u.v.u)) != 0)
return simplify(LSH, ty, r, cnsttree(inttype, (long)n));
foldcnst(U,u,*);
identity(r,l,U,u,1);
break;
case NE+I:
cfoldcnst(I,i,!=);
commute(r,l);
zerofield(NE,I,i);
break;
case EQ+I:
cfoldcnst(I,i,==);
commute(r,l);
zerofield(EQ,I,i);
break;
case ADD+P:
foldaddp(l,r,I,i);
foldaddp(l,r,U,u);
foldaddp(r,l,I,i);
foldaddp(r,l,U,u);
commute(r,l);
identity(r,retype(l,ty),I,i,0);
identity(r,retype(l,ty),U,u,0);
if (isaddrop(l->op)
&& ((r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i
&& r->u.v.i >= longtype->u.sym->u.limits.min.i)
|| (r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i)))
return addrtree(l, cast(r, longtype)->u.v.i, ty);
if (l->op == ADD+P && isaddrop(l->kids[1]->op)
&& ((r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i
&& r->u.v.i >= longtype->u.sym->u.limits.min.i)
|| (r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i)))
return simplify(ADD+P, ty, l->kids[0],
addrtree(l->kids[1], cast(r, longtype)->u.v.i, ty));
if ((l->op == ADD+I || l->op == SUB+I)
&& l->kids[1]->op == CNST+I && isaddrop(r->op))
return simplify(ADD+P, ty, l->kids[0],
simplify(generic(l->op)+P, ty, r, l->kids[1]));
if (l->op == ADD+P && generic(l->kids[1]->op) == CNST
&& generic(r->op) == CNST)
return simplify(ADD+P, ty, l->kids[0],
simplify(ADD, l->kids[1]->type, l->kids[1], r));
if (l->op == ADD+I && generic(l->kids[1]->op) == CNST
&& r->op == ADD+P && generic(r->kids[1]->op) == CNST)
return simplify(ADD+P, ty, l->kids[0],
simplify(ADD+P, ty, r->kids[0],
simplify(ADD, r->kids[1]->type, l->kids[1], r->kids[1])));
if (l->op == RIGHT && l->kids[1])
return tree(RIGHT, ty, l->kids[0],
simplify(ADD+P, ty, l->kids[1], r));
else if (l->op == RIGHT && l->kids[0])
return tree(RIGHT, ty,
simplify(ADD+P, ty, l->kids[0], r), NULL);
break;
case ADD+F:
xfoldcnst(F,d,+,addd);
commute(r,l);
break;
case AND+I:
op = AND;
ufoldcnst(I,l->u.v.i ? cond(r) : l); /* 0&&r => 0, 1&&r => r */
break;
case OR+I:
op = OR;
/* 0||r => r, 1||r => 1 */
ufoldcnst(I,l->u.v.i ? cnsttree(ty, 1L) : cond(r));
break;
case BCOM+I:
ufoldcnst(I,cnsttree(ty, (long)extend((~l->u.v.i)&ones(8*ty->size), ty)));
idempotent(BCOM+U);
break;
case BCOM+U:
ufoldcnst(U,cnsttree(ty, (unsigned long)((~l->u.v.u)&ones(8*ty->size))));
idempotent(BCOM+U);
break;
case BOR+U:
foldcnst(U,u,|);
commute(r,l);
identity(r,l,U,u,0);
break;
case BOR+I:
foldcnst(I,i,|);
commute(r,l);
identity(r,l,I,i,0);
break;
case BXOR+U:
foldcnst(U,u,^);
commute(r,l);
identity(r,l,U,u,0);
break;
case BXOR+I:
foldcnst(I,i,^);
commute(r,l);
identity(r,l,I,i,0);
break;
case DIV+F:
xfoldcnst(F,d,/,divd);
break;
case DIV+I:
identity(r,l,I,i,1);
if ((r->op == CNST+I && r->u.v.i == 0)
|| (l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i
&& r->op == CNST+I && r->u.v.i == -1))
break;
xfoldcnst(I,i,/,divi);
break;
case DIV+U:
identity(r,l,U,u,1);
if (r->op == CNST+U && r->u.v.u == 0)
break;
if (r->op == CNST+U && (n = ispow2(r->u.v.u)) != 0)
return simplify(RSH, ty, l, cnsttree(inttype, (long)n));
foldcnst(U,u,/);
break;
case EQ+F:
cfoldcnst(F,d,==);
commute(r,l);
break;
case EQ+U:
cfoldcnst(U,u,==);
commute(r,l);
zerofield(EQ,U,u);
break;
case GE+F: cfoldcnst(F,d,>=); break;
case GE+I: cfoldcnst(I,i,>=); break;
case GE+U:
geu(l,r,1); /* l >= 0 => (l,1) */
cfoldcnst(U,u,>=);
if (l->op == CNST+U && l->u.v.u == 0) /* 0 >= r => r == 0 */
return eqtree(EQ, r, l);
break;
case GT+F: cfoldcnst(F,d, >); break;
case GT+I: cfoldcnst(I,i, >); break;
case GT+U:
geu(r,l,0); /* 0 > r => (r,0) */
cfoldcnst(U,u, >);
if (r->op == CNST+U && r->u.v.u == 0) /* l > 0 => l != 0 */
return eqtree(NE, l, r);
break;
case LE+F: cfoldcnst(F,d,<=); break;
case LE+I: cfoldcnst(I,i,<=); break;
case LE+U:
geu(r,l,1); /* 0 <= r => (r,1) */
cfoldcnst(U,u,<=);
if (r->op == CNST+U && r->u.v.u == 0) /* l <= 0 => l == 0 */
return eqtree(EQ, l, r);
break;
case LSH+I:
identity(r,l,I,i,0);
if (l->op == CNST+I && r->op == CNST+I
&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size
&& muli(l->u.v.i, 1<<r->u.v.i, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i, needconst))
return cnsttree(ty, (long)(l->u.v.i<<r->u.v.i));
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
break;
}
break;
case LSH+U:
identity(r,l,I,i,0);
sfoldcnst(<<);
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
break;
}
break;
case LT+F: cfoldcnst(F,d, <); break;
case LT+I: cfoldcnst(I,i, <); break;
case LT+U:
geu(l,r,0); /* l < 0 => (l,0) */
cfoldcnst(U,u, <);
if (l->op == CNST+U && l->u.v.u == 0) /* 0 < r => r != 0 */
return eqtree(NE, r, l);
break;
case MOD+I:
if (r->op == CNST+I && r->u.v.i == 1) /* l%1 => (l,0) */
return tree(RIGHT, ty, root(l), cnsttree(ty, 0L));
if ((r->op == CNST+I && r->u.v.i == 0)
|| (l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i
&& r->op == CNST+I && r->u.v.i == -1))
break;
xfoldcnst(I,i,%,divi);
break;
case MOD+U:
if (r->op == CNST+U && ispow2(r->u.v.u)) /* l%2^n => l&(2^n-1) */
return bittree(BAND, l, cnsttree(ty, r->u.v.u - 1));
if (r->op == CNST+U && r->u.v.u == 0)
break;
foldcnst(U,u,%);
break;
case MUL+F:
xfoldcnst(F,d,*,muld);
commute(l,r);
break;
case MUL+I:
commute(l,r);
xfoldcnst(I,i,*,muli);
if (l->op == CNST+I && r->op == ADD+I && r->kids[1]->op == CNST+I)
/* c1*(x + c2) => c1*x + c1*c2 */
return simplify(ADD, ty, simplify(MUL, ty, l, r->kids[0]),
simplify(MUL, ty, l, r->kids[1]));
if (l->op == CNST+I && r->op == SUB+I && r->kids[1]->op == CNST+I)
/* c1*(x - c2) => c1*x - c1*c2 */
return simplify(SUB, ty, simplify(MUL, ty, l, r->kids[0]),
simplify(MUL, ty, l, r->kids[1]));
if (l->op == CNST+I && l->u.v.i > 0 && (n = ispow2(l->u.v.i)) != 0)
/* 2^n * r => r<<n */
return simplify(LSH, ty, r, cnsttree(inttype, (long)n));
identity(r,l,I,i,1);
break;
case NE+F:
cfoldcnst(F,d,!=);
commute(r,l);
break;
case NE+U:
cfoldcnst(U,u,!=);
commute(r,l);
zerofield(NE,U,u);
break;
case NEG+F:
ufoldcnst(F,cnsttree(ty, -l->u.v.d));
idempotent(NEG+F);
break;
case NEG+I:
if (l->op == CNST+I) {
if (needconst && l->u.v.i == ty->u.sym->u.limits.min.i)
warning("overflow in constant expression\n");
if (needconst || l->u.v.i != ty->u.sym->u.limits.min.i)
return cnsttree(ty, -l->u.v.i);
}
idempotent(NEG+I);
break;
case NOT+I:
op = NOT;
ufoldcnst(I,cnsttree(ty, !l->u.v.i));
break;
case RSH+I:
identity(r,l,I,i,0);
if (l->op == CNST+I && r->op == CNST+I
&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) {
long n = l->u.v.i>>r->u.v.i;
if (l->u.v.i < 0)
n |= ~0UL<<(8*l->type->size - r->u.v.i);
return cnsttree(ty, n);
}
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
break;
}
break;
case RSH+U:
identity(r,l,I,i,0);
sfoldcnst(>>);
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
break;
}
break;
case SUB+F:
xfoldcnst(F,d,-,subd);
break;
case SUB+I:
xfoldcnst(I,i,-,subi);
identity(r,l,I,i,0);
break;
case SUB+U:
foldcnst(U,u,-);
identity(r,l,U,u,0);
break;
case SUB+P:
if (l->op == CNST+P && r->op == CNST+P)
return cnsttree(ty, (long)((char *)l->u.v.p - (char *)r->u.v.p));
if (r->op == CNST+I || r->op == CNST+U)
return simplify(ADD, ty, l,
cnsttree(inttype, r->op == CNST+I ? -r->u.v.i : -(long)r->u.v.u));
if (isaddrop(l->op) && r->op == ADD+I && r->kids[1]->op == CNST+I)
/* l - (x + c) => l-c - x */
return simplify(SUB, ty,
simplify(SUB, ty, l, r->kids[1]), r->kids[0]);
break;
default:assert(0);
}
return tree(op, ty, l, r);
}
/* ispow2 - if u > 1 && u == 2^n, return n, otherwise return 0 */
int ispow2(unsigned long u) {
int n;
if (u > 1 && (u&(u-1)) == 0)
for (n = 0; u; u >>= 1, n++)
if (u&1)
return n;
return 0;
}

View File

@@ -1,696 +0,0 @@
#include "c.h"
#define SWSIZE 512
#define den(i,j) ((j-buckets[i]+1.0)/(v[j]-v[buckets[i]]+1))
struct code codehead = { Start };
Code codelist = &codehead;
float density = 0.5;
Table stmtlabs;
static int foldcond(Tree e1, Tree e2);
static void caselabel(Swtch, long, int);
static void cmp(int, Symbol, long, int);
static Tree conditional(int);
static void dostmt(int, Swtch, int);
static int equal(Symbol, Symbol);
static void forstmt(int, Swtch, int);
static void ifstmt(int, int, Swtch, int);
static Symbol localaddr(Tree);
static void stmtlabel(void);
static void swstmt(int, int, int);
static void whilestmt(int, Swtch, int);
Code code(int kind) {
Code cp;
if (!reachable(kind))
warning("unreachable code\n");
NEW(cp, FUNC);
cp->kind = kind;
cp->prev = codelist;
cp->next = NULL;
codelist->next = cp;
codelist = cp;
return cp;
}
int reachable(int kind) {
if (kind > Start) {
Code cp;
for (cp = codelist; cp->kind < Label; )
cp = cp->prev;
if (cp->kind == Jump || cp->kind == Switch)
return 0;
}
return 1;
}
void addlocal(Symbol p) {
if (!p->defined) {
code(Local)->u.var = p;
p->defined = 1;
p->scope = level;
}
}
void definept(Coordinate *p) {
Code cp = code(Defpoint);
cp->u.point.src = p ? *p : src;
cp->u.point.point = npoints;
if (ncalled > 0) {
int n = findcount(cp->u.point.src.file,
cp->u.point.src.x, cp->u.point.src.y);
if (n > 0)
refinc = (float)n/ncalled;
}
if (glevel > 2) locus(identifiers, &cp->u.point.src);
if (events.points && reachable(Gen))
{
Tree e = NULL;
apply(events.points, &cp->u.point.src, &e);
if (e)
listnodes(e, 0, 0);
}
}
void statement(int loop, Swtch swp, int lev) {
float ref = refinc;
if (Aflag >= 2 && lev == 15)
warning("more than 15 levels of nested statements\n");
switch (t) {
case IF: ifstmt(genlabel(2), loop, swp, lev + 1);
break;
case WHILE: whilestmt(genlabel(3), swp, lev + 1); break;
case DO: dostmt(genlabel(3), swp, lev + 1); expect(';');
break;
case FOR: forstmt(genlabel(4), swp, lev + 1);
break;
case BREAK: walk(NULL, 0, 0);
definept(NULL);
if (swp && swp->lab > loop)
branch(swp->lab + 1);
else if (loop)
branch(loop + 2);
else
error("illegal break statement\n");
t = gettok(); expect(';');
break;
case CONTINUE: walk(NULL, 0, 0);
definept(NULL);
if (loop)
branch(loop + 1);
else
error("illegal continue statement\n");
t = gettok(); expect(';');
break;
case SWITCH: swstmt(loop, genlabel(2), lev + 1);
break;
case CASE: {
int lab = genlabel(1);
if (swp == NULL)
error("illegal case label\n");
definelab(lab);
while (t == CASE) {
static char stop[] = { IF, ID, 0 };
Tree p;
t = gettok();
p = constexpr(0);
if (generic(p->op) == CNST && isint(p->type)) {
if (swp) {
needconst++;
p = cast(p, swp->sym->type);
if (p->type->op == UNSIGNED)
p->u.v.i = extend(p->u.v.u, p->type);
needconst--;
caselabel(swp, p->u.v.i, lab);
}
} else
error("case label must be a constant integer expression\n");
test(':', stop);
}
statement(loop, swp, lev);
} break;
case DEFAULT: if (swp == NULL)
error("illegal default label\n");
else if (swp->deflab)
error("extra default label\n");
else {
swp->deflab = findlabel(swp->lab);
definelab(swp->deflab->u.l.label);
}
t = gettok();
expect(':');
statement(loop, swp, lev); break;
case RETURN: {
Type rty = freturn(cfunc->type);
t = gettok();
definept(NULL);
if (t != ';')
if (rty == voidtype) {
error("extraneous return value\n");
expr(0);
retcode(NULL);
} else
retcode(expr(0));
else {
if (rty != voidtype)
warning("missing return value\n");
retcode(NULL);
}
branch(cfunc->u.f.label);
} expect(';');
break;
case '{': compound(loop, swp, lev + 1); break;
case ';': definept(NULL); t = gettok(); break;
case GOTO: walk(NULL, 0, 0);
definept(NULL);
t = gettok();
if (t == ID) {
Symbol p = lookup(token, stmtlabs);
if (p == NULL) {
p = install(token, &stmtlabs, 0, FUNC);
p->scope = LABELS;
p->u.l.label = genlabel(1);
p->src = src;
}
use(p, src);
branch(p->u.l.label);
t = gettok();
} else
error("missing label in goto\n"); expect(';');
break;
case ID: if (getchr() == ':') {
stmtlabel();
statement(loop, swp, lev);
break;
}
default: definept(NULL);
if (kind[t] != ID) {
error("unrecognized statement\n");
t = gettok();
} else {
Tree e = expr0(0);
listnodes(e, 0, 0);
if (nodecount == 0 || nodecount > 200)
walk(NULL, 0, 0);
else if (glevel) walk(NULL, 0, 0);
deallocate(STMT);
} expect(';');
break;
}
if (kind[t] != IF && kind[t] != ID
&& t != '}' && t != EOI) {
static char stop[] = { IF, ID, '}', 0 };
error("illegal statement termination\n");
skipto(0, stop);
}
refinc = ref;
}
static void ifstmt(int lab, int loop, Swtch swp, int lev) {
t = gettok();
expect('(');
definept(NULL);
walk(conditional(')'), 0, lab);
refinc /= 2.0;
statement(loop, swp, lev);
if (t == ELSE) {
branch(lab + 1);
t = gettok();
definelab(lab);
statement(loop, swp, lev);
if (findlabel(lab + 1)->ref)
definelab(lab + 1);
} else
definelab(lab);
}
static Tree conditional(int tok) {
Tree p = expr(tok);
if (Aflag > 1 && isfunc(p->type))
warning("%s used in a conditional expression\n",
funcname(p));
return cond(p);
}
static void stmtlabel(void) {
Symbol p = lookup(token, stmtlabs);
if (p == NULL) {
p = install(token, &stmtlabs, 0, FUNC);
p->scope = LABELS;
p->u.l.label = genlabel(1);
p->src = src;
}
if (p->defined)
error("redefinition of label `%s' previously defined at %w\n", p->name, &p->src);
p->defined = 1;
definelab(p->u.l.label);
t = gettok();
expect(':');
}
static void forstmt(int lab, Swtch swp, int lev) {
int once = 0;
Tree e1 = NULL, e2 = NULL, e3 = NULL;
Coordinate pt2, pt3;
t = gettok();
expect('(');
definept(NULL);
if (kind[t] == ID)
e1 = texpr(expr0, ';', FUNC);
else
expect(';');
walk(e1, 0, 0);
pt2 = src;
refinc *= 10.0;
if (kind[t] == ID)
e2 = texpr(conditional, ';', FUNC);
else
expect(';');
pt3 = src;
if (kind[t] == ID)
e3 = texpr(expr0, ')', FUNC);
else {
static char stop[] = { IF, ID, '}', 0 };
test(')', stop);
}
if (e2) {
once = foldcond(e1, e2);
if (!once)
branch(lab + 3);
}
definelab(lab);
statement(lab, swp, lev);
definelab(lab + 1);
definept(&pt3);
if (e3)
walk(e3, 0, 0);
if (e2) {
if (!once)
definelab(lab + 3);
definept(&pt2);
walk(e2, lab, 0);
} else {
definept(&pt2);
branch(lab);
}
if (findlabel(lab + 2)->ref)
definelab(lab + 2);
}
static void swstmt(int loop, int lab, int lev) {
Tree e;
struct swtch sw;
Code head, tail;
t = gettok();
expect('(');
definept(NULL);
e = expr(')');
if (!isint(e->type)) {
error("illegal type `%t' in switch expression\n",
e->type);
e = retype(e, inttype);
}
e = cast(e, promote(e->type));
if (generic(e->op) == INDIR && isaddrop(e->kids[0]->op)
&& e->kids[0]->u.sym->type == e->type
&& !isvolatile(e->kids[0]->u.sym->type)) {
sw.sym = e->kids[0]->u.sym;
walk(NULL, 0, 0);
} else {
sw.sym = genident(REGISTER, e->type, level);
addlocal(sw.sym);
walk(asgn(sw.sym, e), 0, 0);
}
head = code(Switch);
sw.lab = lab;
sw.deflab = NULL;
sw.ncases = 0;
sw.size = SWSIZE;
sw.values = newarray(SWSIZE, sizeof *sw.values, FUNC);
sw.labels = newarray(SWSIZE, sizeof *sw.labels, FUNC);
refinc /= 10.0;
statement(loop, &sw, lev);
if (sw.deflab == NULL) {
sw.deflab = findlabel(lab);
definelab(lab);
if (sw.ncases == 0)
warning("switch statement with no cases\n");
}
if (findlabel(lab + 1)->ref)
definelab(lab + 1);
tail = codelist;
codelist = head->prev;
codelist->next = head->prev = NULL;
if (sw.ncases > 0)
swgen(&sw);
branch(lab);
head->next->prev = codelist;
codelist->next = head->next;
codelist = tail;
}
static void caselabel(Swtch swp, long val, int lab) {
int k;
if (swp->ncases >= swp->size)
{
long *vals = swp->values;
Symbol *labs = swp->labels;
swp->size *= 2;
swp->values = newarray(swp->size, sizeof *swp->values, FUNC);
swp->labels = newarray(swp->size, sizeof *swp->labels, FUNC);
for (k = 0; k < swp->ncases; k++) {
swp->values[k] = vals[k];
swp->labels[k] = labs[k];
}
}
k = swp->ncases;
for ( ; k > 0 && swp->values[k-1] >= val; k--) {
swp->values[k] = swp->values[k-1];
swp->labels[k] = swp->labels[k-1];
}
if (k < swp->ncases && swp->values[k] == val)
error("duplicate case label `%d'\n", val);
swp->values[k] = val;
swp->labels[k] = findlabel(lab);
++swp->ncases;
if (Aflag >= 2 && swp->ncases == 258)
warning("more than 257 cases in a switch\n");
}
void swgen(Swtch swp) {
int *buckets, k, n;
long *v = swp->values;
buckets = newarray(swp->ncases + 1,
sizeof *buckets, FUNC);
for (n = k = 0; k < swp->ncases; k++, n++) {
buckets[n] = k;
while (n > 0 && den(n-1, k) >= density)
n--;
}
buckets[n] = swp->ncases;
swcode(swp, buckets, 0, n - 1);
}
void swcode(Swtch swp, int b[], int lb, int ub) {
int hilab, lolab, l, u, k = (lb + ub)/2;
long *v = swp->values;
if (k > lb && k < ub) {
lolab = genlabel(1);
hilab = genlabel(1);
} else if (k > lb) {
lolab = genlabel(1);
hilab = swp->deflab->u.l.label;
} else if (k < ub) {
lolab = swp->deflab->u.l.label;
hilab = genlabel(1);
} else
lolab = hilab = swp->deflab->u.l.label;
l = b[k];
u = b[k+1] - 1;
if (u - l + 1 <= 3)
{
int i;
for (i = l; i <= u; i++)
cmp(EQ, swp->sym, v[i], swp->labels[i]->u.l.label);
if (k > lb && k < ub)
cmp(GT, swp->sym, v[u], hilab);
else if (k > lb)
cmp(GT, swp->sym, v[u], hilab);
else if (k < ub)
cmp(LT, swp->sym, v[l], lolab);
else
assert(lolab == hilab),
branch(lolab);
walk(NULL, 0, 0);
}
else {
Tree e;
Type ty = signedint(swp->sym->type);
Symbol table = genident(STATIC,
array(voidptype, u - l + 1, 0), GLOBAL);
(*IR->defsymbol)(table);
if (!isunsigned(swp->sym->type) || v[l] != 0)
cmp(LT, swp->sym, v[l], lolab);
cmp(GT, swp->sym, v[u], hilab);
e = (*optree['-'])(SUB, cast(idtree(swp->sym), ty), cnsttree(ty, v[l]));
if (e->type->size < unsignedptr->size)
e = cast(e, unsignedlong);
walk(tree(JUMP, voidtype,
rvalue((*optree['+'])(ADD, pointer(idtree(table)), e)), NULL),
0, 0);
code(Switch);
codelist->u.swtch.table = table;
codelist->u.swtch.sym = swp->sym;
codelist->u.swtch.deflab = swp->deflab;
codelist->u.swtch.size = u - l + 1;
codelist->u.swtch.values = &v[l];
codelist->u.swtch.labels = &swp->labels[l];
if (v[u] - v[l] + 1 >= 10000)
warning("switch generates a huge table\n");
}
if (k > lb) {
assert(lolab != swp->deflab->u.l.label);
definelab(lolab);
swcode(swp, b, lb, k - 1);
}
if (k < ub) {
assert(hilab != swp->deflab->u.l.label);
definelab(hilab);
swcode(swp, b, k + 1, ub);
}
}
static void cmp(int op, Symbol p, long n, int lab) {
Type ty = signedint(p->type);
listnodes(eqtree(op,
cast(idtree(p), ty),
cnsttree(ty, n)),
lab, 0);
}
void retcode(Tree p) {
Type ty;
if (p == NULL) {
if (events.returns)
apply(events.returns, cfunc, NULL);
return;
}
p = pointer(p);
ty = assign(freturn(cfunc->type), p);
if (ty == NULL) {
error("illegal return type; found `%t' expected `%t'\n",
p->type, freturn(cfunc->type));
return;
}
p = cast(p, ty);
if (retv)
{
if (iscallb(p))
p = tree(RIGHT, p->type,
tree(CALL+B, p->type,
p->kids[0]->kids[0], idtree(retv)),
rvalue(idtree(retv)));
else
p = asgntree(ASGN, rvalue(idtree(retv)), p);
walk(p, 0, 0);
if (events.returns)
apply(events.returns, cfunc, rvalue(idtree(retv)));
return;
}
if (events.returns)
{
Symbol t1 = genident(AUTO, p->type, level);
addlocal(t1);
walk(asgn(t1, p), 0, 0);
apply(events.returns, cfunc, idtree(t1));
p = idtree(t1);
}
if (!isfloat(p->type))
p = cast(p, promote(p->type));
if (isptr(p->type))
{
Symbol q = localaddr(p);
if (q && (q->computed || q->generated))
warning("pointer to a %s is an illegal return value\n",
q->scope == PARAM ? "parameter" : "local");
else if (q)
warning("pointer to %s `%s' is an illegal return value\n",
q->scope == PARAM ? "parameter" : "local", q->name);
}
walk(tree(mkop(RET,p->type), p->type, p, NULL), 0, 0);
}
void definelab(int lab) {
Code cp;
Symbol p = findlabel(lab);
assert(lab);
walk(NULL, 0, 0);
code(Label)->u.forest = newnode(LABEL+V, NULL, NULL, p);
for (cp = codelist->prev; cp->kind <= Label; )
cp = cp->prev;
while ( cp->kind == Jump
&& cp->u.forest->kids[0]
&& specific(cp->u.forest->kids[0]->op) == ADDRG+P
&& cp->u.forest->kids[0]->syms[0] == p) {
assert(cp->u.forest->kids[0]->syms[0]->u.l.label == lab);
p->ref--;
assert(cp->next);
assert(cp->prev);
cp->prev->next = cp->next;
cp->next->prev = cp->prev;
cp = cp->prev;
while (cp->kind <= Label)
cp = cp->prev;
}
}
Node jump(int lab) {
Symbol p = findlabel(lab);
p->ref++;
return newnode(JUMP+V, newnode(ADDRG+ttob(voidptype), NULL, NULL, p),
NULL, NULL);
}
void branch(int lab) {
Code cp;
Symbol p = findlabel(lab);
assert(lab);
walk(NULL, 0, 0);
code(Label)->u.forest = jump(lab);
for (cp = codelist->prev; cp->kind < Label; )
cp = cp->prev;
while ( cp->kind == Label
&& cp->u.forest->op == LABEL+V
&& !equal(cp->u.forest->syms[0], p)) {
equatelab(cp->u.forest->syms[0], p);
assert(cp->next);
assert(cp->prev);
cp->prev->next = cp->next;
cp->next->prev = cp->prev;
cp = cp->prev;
while (cp->kind < Label)
cp = cp->prev;
}
if (cp->kind == Jump || cp->kind == Switch) {
p->ref--;
codelist->prev->next = NULL;
codelist = codelist->prev;
} else {
codelist->kind = Jump;
if (cp->kind == Label
&& cp->u.forest->op == LABEL+V
&& equal(cp->u.forest->syms[0], p))
warning("source code specifies an infinite loop");
}
}
void equatelab(Symbol old, Symbol new) {
assert(old->u.l.equatedto == NULL);
old->u.l.equatedto = new;
new->ref++;
}
static int equal(Symbol lprime, Symbol dst) {
assert(dst && lprime);
for ( ; dst; dst = dst->u.l.equatedto)
if (lprime == dst)
return 1;
return 0;
}
/* dostmt - do statement while ( expression ) */
static void dostmt(int lab, Swtch swp, int lev) {
refinc *= 10.0;
t = gettok();
definelab(lab);
statement(lab, swp, lev);
definelab(lab + 1);
expect(WHILE);
expect('(');
definept(NULL);
walk(conditional(')'), lab, 0);
if (findlabel(lab + 2)->ref)
definelab(lab + 2);
}
/* foldcond - check if initial test in for(e1;e2;e3) S is necessary */
static int foldcond(Tree e1, Tree e2) {
int op = generic(e2->op);
Symbol v;
if (e1 == 0 || e2 == 0)
return 0;
if (generic(e1->op) == ASGN && isaddrop(e1->kids[0]->op)
&& generic(e1->kids[1]->op) == CNST) {
v = e1->kids[0]->u.sym;
e1 = e1->kids[1];
} else
return 0;
if ((op==LE || op==LT || op==EQ || op==NE || op==GT || op==GE)
&& generic(e2->kids[0]->op) == INDIR
&& e2->kids[0]->kids[0]->u.sym == v
&& e2->kids[1]->op == e1->op) {
e1 = simplify(op, e2->type, e1, e2->kids[1]);
if (e1->op == CNST+I)
return e1->u.v.i;
}
return 0;
}
/* localaddr - returns q if p yields the address of local/parameter q; otherwise returns 0 */
static Symbol localaddr(Tree p) {
if (p == NULL)
return NULL;
switch (generic(p->op)) {
case INDIR: case CALL: case ARG:
return NULL;
case ADDRL: case ADDRF:
return p->u.sym;
case RIGHT: case ASGN:
if (p->kids[1])
return localaddr(p->kids[1]);
return localaddr(p->kids[0]);
case COND: {
Symbol q;
assert(p->kids[1] && p->kids[1]->op == RIGHT);
if ((q = localaddr(p->kids[1]->kids[0])) != NULL)
return q;
return localaddr(p->kids[1]->kids[1]);
}
default: {
Symbol q;
if (p->kids[0] && (q = localaddr(p->kids[0])) != NULL)
return q;
return localaddr(p->kids[1]);
}
}
}
/* whilestmt - while ( expression ) statement */
static void whilestmt(int lab, Swtch swp, int lev) {
Coordinate pt;
Tree e;
refinc *= 10.0;
t = gettok();
expect('(');
walk(NULL, 0, 0);
pt = src;
e = texpr(conditional, ')', FUNC);
branch(lab + 1);
definelab(lab);
statement(lab, swp, lev);
definelab(lab + 1);
definept(&pt);
walk(e, lab, 0);
if (findlabel(lab + 2)->ref)
definelab(lab + 2);
}

View File

@@ -1,122 +0,0 @@
#include "c.h"
static struct string {
char *str;
int len;
struct string *link;
} *buckets[1024];
static int scatter[] = { /* map characters to random values */
2078917053, 143302914, 1027100827, 1953210302, 755253631,
2002600785, 1405390230, 45248011, 1099951567, 433832350,
2018585307, 438263339, 813528929, 1703199216, 618906479,
573714703, 766270699, 275680090, 1510320440, 1583583926,
1723401032, 1965443329, 1098183682, 1636505764, 980071615,
1011597961, 643279273, 1315461275, 157584038, 1069844923,
471560540, 89017443, 1213147837, 1498661368, 2042227746,
1968401469, 1353778505, 1300134328, 2013649480, 306246424,
1733966678, 1884751139, 744509763, 400011959, 1440466707,
1363416242, 973726663, 59253759, 1639096332, 336563455,
1642837685, 1215013716, 154523136, 593537720, 704035832,
1134594751, 1605135681, 1347315106, 302572379, 1762719719,
269676381, 774132919, 1851737163, 1482824219, 125310639,
1746481261, 1303742040, 1479089144, 899131941, 1169907872,
1785335569, 485614972, 907175364, 382361684, 885626931,
200158423, 1745777927, 1859353594, 259412182, 1237390611,
48433401, 1902249868, 304920680, 202956538, 348303940,
1008956512, 1337551289, 1953439621, 208787970, 1640123668,
1568675693, 478464352, 266772940, 1272929208, 1961288571,
392083579, 871926821, 1117546963, 1871172724, 1771058762,
139971187, 1509024645, 109190086, 1047146551, 1891386329,
994817018, 1247304975, 1489680608, 706686964, 1506717157,
579587572, 755120366, 1261483377, 884508252, 958076904,
1609787317, 1893464764, 148144545, 1415743291, 2102252735,
1788268214, 836935336, 433233439, 2055041154, 2109864544,
247038362, 299641085, 834307717, 1364585325, 23330161,
457882831, 1504556512, 1532354806, 567072918, 404219416,
1276257488, 1561889936, 1651524391, 618454448, 121093252,
1010757900, 1198042020, 876213618, 124757630, 2082550272,
1834290522, 1734544947, 1828531389, 1982435068, 1002804590,
1783300476, 1623219634, 1839739926, 69050267, 1530777140,
1802120822, 316088629, 1830418225, 488944891, 1680673954,
1853748387, 946827723, 1037746818, 1238619545, 1513900641,
1441966234, 367393385, 928306929, 946006977, 985847834,
1049400181, 1956764878, 36406206, 1925613800, 2081522508,
2118956479, 1612420674, 1668583807, 1800004220, 1447372094,
523904750, 1435821048, 923108080, 216161028, 1504871315,
306401572, 2018281851, 1820959944, 2136819798, 359743094,
1354150250, 1843084537, 1306570817, 244413420, 934220434,
672987810, 1686379655, 1301613820, 1601294739, 484902984,
139978006, 503211273, 294184214, 176384212, 281341425,
228223074, 147857043, 1893762099, 1896806882, 1947861263,
1193650546, 273227984, 1236198663, 2116758626, 489389012,
593586330, 275676551, 360187215, 267062626, 265012701,
719930310, 1621212876, 2108097238, 2026501127, 1865626297,
894834024, 552005290, 1404522304, 48964196, 5816381,
1889425288, 188942202, 509027654, 36125855, 365326415,
790369079, 264348929, 513183458, 536647531, 13672163,
313561074, 1730298077, 286900147, 1549759737, 1699573055,
776289160, 2143346068, 1975249606, 1136476375, 262925046,
92778659, 1856406685, 1884137923, 53392249, 1735424165,
1602280572
};
char *string(const char *str) {
const char *s;
for (s = str; *s; s++)
;
return stringn(str, s - str);
}
char *stringd(long n) {
char str[25], *s = str + sizeof (str);
unsigned long m;
if (n == LONG_MIN)
m = (unsigned long)LONG_MAX + 1;
else if (n < 0)
m = -n;
else
m = n;
do
*--s = m%10 + '0';
while ((m /= 10) != 0);
if (n < 0)
*--s = '-';
return stringn(s, str + sizeof (str) - s);
}
char *stringn(const char *str, int len) {
int i;
unsigned int h;
const char *end;
struct string *p;
assert(str);
for (h = 0, i = len, end = str; i > 0; i--)
h = (h<<1) + scatter[*(unsigned char *)end++];
h &= NELEMS(buckets)-1;
for (p = buckets[h]; p; p = p->link)
if (len == p->len) {
const char *s1 = str;
char *s2 = p->str;
do {
if (s1 == end)
return p->str;
} while (*s1++ == *s2++);
}
{
static char *next, *strlimit;
if (len + 1 >= strlimit - next) {
int n = len + 4*1024;
next = allocate(n, PERM);
strlimit = next + n;
}
NEW(p, PERM);
p->len = len;
for (p->str = next; str < end; )
*next++ = *str++;
*next++ = 0;
p->link = buckets[h];
buckets[h] = p;
return p->str;
}
}

View File

@@ -1,314 +0,0 @@
#include "c.h"
#include <stdio.h>
#define equalp(x) v.x == p->sym.u.c.v.x
struct table {
int level;
Table previous;
struct entry {
struct symbol sym;
struct entry *link;
} *buckets[256];
Symbol all;
};
#define HASHSIZE NELEMS(((Table)0)->buckets)
static struct table
cns = { CONSTANTS },
ext = { GLOBAL },
ids = { GLOBAL },
tys = { GLOBAL };
Table constants = &cns;
Table externals = &ext;
Table identifiers = &ids;
Table globals = &ids;
Table types = &tys;
Table labels;
int level = GLOBAL;
static int tempid;
List loci, symbols;
Table table(Table tp, int level) {
Table new;
NEW0(new, FUNC);
new->previous = tp;
new->level = level;
if (tp)
new->all = tp->all;
return new;
}
void foreach(Table tp, int lev, void (*apply)(Symbol, void *), void *cl) {
assert(tp);
while (tp && tp->level > lev)
tp = tp->previous;
if (tp && tp->level == lev) {
Symbol p;
Coordinate sav;
sav = src;
for (p = tp->all; p && p->scope == lev; p = p->up) {
src = p->src;
(*apply)(p, cl);
}
src = sav;
}
}
void enterscope(void) {
if (++level == LOCAL)
tempid = 0;
}
void exitscope(void) {
rmtypes(level);
if (types->level == level)
types = types->previous;
if (identifiers->level == level) {
if (Aflag >= 2) {
int n = 0;
Symbol p;
for (p = identifiers->all; p && p->scope == level; p = p->up)
if (++n > 127) {
warning("more than 127 identifiers declared in a block\n");
break;
}
}
identifiers = identifiers->previous;
}
assert(level >= GLOBAL);
--level;
}
Symbol install(const char *name, Table *tpp, int level, int arena) {
Table tp = *tpp;
struct entry *p;
unsigned h = (unsigned long)name&(HASHSIZE-1);
assert(level == 0 || level >= tp->level);
if (level > 0 && tp->level < level)
tp = *tpp = table(tp, level);
NEW0(p, arena);
p->sym.name = (char *)name;
p->sym.scope = level;
p->sym.up = tp->all;
tp->all = &p->sym;
p->link = tp->buckets[h];
tp->buckets[h] = p;
return &p->sym;
}
Symbol relocate(const char *name, Table src, Table dst) {
struct entry *p, **q;
Symbol *r;
unsigned h = (unsigned long)name&(HASHSIZE-1);
for (q = &src->buckets[h]; *q; q = &(*q)->link)
if (name == (*q)->sym.name)
break;
assert(*q);
/*
Remove the entry from src's hash chain
and from its list of all symbols.
*/
p = *q;
*q = (*q)->link;
for (r = &src->all; *r && *r != &p->sym; r = &(*r)->up)
;
assert(*r == &p->sym);
*r = p->sym.up;
/*
Insert the entry into dst's hash chain
and into its list of all symbols.
Return the symbol-table entry.
*/
p->link = dst->buckets[h];
dst->buckets[h] = p;
p->sym.up = dst->all;
dst->all = &p->sym;
return &p->sym;
}
Symbol lookup(const char *name, Table tp) {
struct entry *p;
unsigned h = (unsigned long)name&(HASHSIZE-1);
assert(tp);
do
for (p = tp->buckets[h]; p; p = p->link)
if (name == p->sym.name)
return &p->sym;
while ((tp = tp->previous) != NULL);
return NULL;
}
int genlabel(int n) {
static int label = 1;
label += n;
return label - n;
}
Symbol findlabel(int lab) {
struct entry *p;
unsigned h = lab&(HASHSIZE-1);
for (p = labels->buckets[h]; p; p = p->link)
if (lab == p->sym.u.l.label)
return &p->sym;
NEW0(p, FUNC);
p->sym.name = stringd(lab);
p->sym.scope = LABELS;
p->sym.up = labels->all;
labels->all = &p->sym;
p->link = labels->buckets[h];
labels->buckets[h] = p;
p->sym.generated = 1;
p->sym.u.l.label = lab;
(*IR->defsymbol)(&p->sym);
return &p->sym;
}
Symbol constant(Type ty, Value v) {
struct entry *p;
unsigned h = v.u&(HASHSIZE-1);
ty = unqual(ty);
for (p = constants->buckets[h]; p; p = p->link)
if (eqtype(ty, p->sym.type, 1))
switch (ty->op) {
case INT: if (equalp(i)) return &p->sym; break;
case UNSIGNED: if (equalp(u)) return &p->sym; break;
case FLOAT: if (equalp(d)) return &p->sym; break;
case FUNCTION: if (equalp(g)) return &p->sym; break;
case ARRAY:
case POINTER: if (equalp(p)) return &p->sym; break;
default: assert(0);
}
NEW0(p, PERM);
p->sym.name = vtoa(ty, v);
p->sym.scope = CONSTANTS;
p->sym.type = ty;
p->sym.sclass = STATIC;
p->sym.u.c.v = v;
p->link = constants->buckets[h];
p->sym.up = constants->all;
constants->all = &p->sym;
constants->buckets[h] = p;
if (ty->u.sym && !ty->u.sym->addressed)
(*IR->defsymbol)(&p->sym);
p->sym.defined = 1;
return &p->sym;
}
Symbol intconst(int n) {
Value v;
v.i = n;
return constant(inttype, v);
}
Symbol genident(int scls, Type ty, int lev) {
Symbol p;
NEW0(p, lev >= LOCAL ? FUNC : PERM);
p->name = stringd(genlabel(1));
p->scope = lev;
p->sclass = scls;
p->type = ty;
p->generated = 1;
if (lev == GLOBAL)
(*IR->defsymbol)(p);
return p;
}
Symbol temporary(int scls, Type ty) {
Symbol p;
NEW0(p, FUNC);
p->name = stringd(++tempid);
p->scope = level < LOCAL ? LOCAL : level;
p->sclass = scls;
p->type = ty;
p->temporary = 1;
p->generated = 1;
return p;
}
Symbol newtemp(int sclass, int tc, int size) {
Symbol p = temporary(sclass, btot(tc, size));
(*IR->local)(p);
p->defined = 1;
return p;
}
Symbol allsymbols(Table tp) {
return tp->all;
}
void locus(Table tp, Coordinate *cp) {
loci = append(cp, loci);
symbols = append(allsymbols(tp), symbols);
}
void use(Symbol p, Coordinate src) {
Coordinate *cp;
NEW(cp, PERM);
*cp = src;
p->uses = append(cp, p->uses);
}
/* findtype - find type ty in identifiers */
Symbol findtype(Type ty) {
Table tp = identifiers;
int i;
struct entry *p;
assert(tp);
do
for (i = 0; i < HASHSIZE; i++)
for (p = tp->buckets[i]; p; p = p->link)
if (p->sym.type == ty && p->sym.sclass == TYPEDEF)
return &p->sym;
while ((tp = tp->previous) != NULL);
return NULL;
}
/* mkstr - make a string constant */
Symbol mkstr(char *str) {
Value v;
Symbol p;
v.p = str;
p = constant(array(chartype, strlen(v.p) + 1, 0), v);
if (p->u.c.loc == NULL)
p->u.c.loc = genident(STATIC, p->type, GLOBAL);
return p;
}
/* mksymbol - make a symbol for name, install in &globals if sclass==EXTERN */
Symbol mksymbol(int sclass, const char *name, Type ty) {
Symbol p;
if (sclass == EXTERN)
p = install(string(name), &globals, GLOBAL, PERM);
else {
NEW0(p, PERM);
p->name = string(name);
p->scope = GLOBAL;
}
p->sclass = sclass;
p->type = ty;
(*IR->defsymbol)(p);
p->defined = 1;
return p;
}
/* vtoa - return string for the constant v of type ty */
char *vtoa(Type ty, Value v) {
ty = unqual(ty);
switch (ty->op) {
case INT: return stringd(v.i);
case UNSIGNED: return stringf((v.u&~0x7FFF) ? "0x%X" : "%U", v.u);
case FLOAT: return stringf("%g", (double)v.d);
case ARRAY:
if (ty->type == chartype || ty->type == signedchar
|| ty->type == unsignedchar)
return v.p;
return stringf("%p", v.p);
case POINTER: return stringf("%p", v.p);
case FUNCTION: return stringf("%p", v.g);
}
assert(0); return NULL;
}

View File

@@ -1,494 +0,0 @@
#include <time.h>
#include <ctype.h>
#include "c.h"
#define I(f) s_##f
static Node *tail;
static int off, maxoff, uid = 0, verbose = 0, html = 0;
static const char *yyBEGIN(const char *tag) {
if (html)
print("<%s>", tag);
return tag;
}
static void yyEND(const char *tag) {
if (html)
print("</%s>", tag);
if (isupper(*tag))
print("\n");
}
#define BEGIN(tag) do { const char *yytag=yyBEGIN(#tag);
#define END yyEND(yytag); } while (0)
#define ITEM BEGIN(li)
#define START BEGIN(LI)
#define ANCHOR(attr,code) do { const char *yytag="a"; if (html) { printf("<a " #attr "=\""); code; print("\">"); }
#define NEWLINE print(html ? "<br>\n" : "\n")
static void emitCoord(Coordinate src) {
if (src.file && *src.file) {
ANCHOR(href,print("%s", src.file)); print("%s", src.file); END;
print(":");
}
print("%d.%d", src.y, src.x);
}
static void emitString(int len, const char *s) {
for ( ; len-- > 0; s++)
if (*s == '&' && html)
print("&amp;");
else if (*s == '<' && html)
print("&lt;");
else if (*s == '>' && html)
print("&lt;");
else if (*s == '"' || *s == '\\')
print("\\%c", *s);
else if (*s >= ' ' && *s < 0177)
print("%c", *s);
else
print("\\%d%d%d", (*s>>6)&3, (*s>>3)&7, *s&7);
}
static void emitSymRef(Symbol p) {
(*IR->defsymbol)(p);
ANCHOR(href,print("#%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
}
static void emitSymbol(Symbol p) {
(*IR->defsymbol)(p);
ANCHOR(name,print("%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
BEGIN(ul);
#define xx(field,code) ITEM; if (!html) print(" "); print(#field "="); code; END
if (verbose && (src.y || src.x))
xx(src,emitCoord(p->src));
xx(type,print("%t", p->type));
xx(sclass,print("%k", p->sclass));
switch (p->scope) {
case CONSTANTS: xx(scope,print("CONSTANTS")); break;
case LABELS: xx(scope,print("LABELS")); break;
case GLOBAL: xx(scope,print("GLOBAL")); break;
case PARAM: xx(scope,print("PARAM")); break;
case LOCAL: xx(scope,print("LOCAL")); break;
default:
if (p->scope > LOCAL)
xx(scope,print("LOCAL+%d", p->scope-LOCAL));
else
xx(scope,print("%d", p->scope));
}
if (p->scope >= PARAM && p->sclass != STATIC)
xx(offset,print("%d", p->x.offset));
xx(ref,print("%f", p->ref));
if (p->temporary && p->u.t.cse)
xx(u.t.cse,print("%p", p->u.t.cse));
END;
#undef xx
}
/* address - initialize q for addressing expression p+n */
static void I(address)(Symbol q, Symbol p, long n) {
q->name = stringf("%s%s%D", p->name, n > 0 ? "+" : "", n);
(*IR->defsymbol)(q);
START; print("address "); emitSymbol(q); END;
}
/* blockbeg - start a block */
static void I(blockbeg)(Env *e) {
e->offset = off;
START; print("blockbeg off=%d", off); END;
}
/* blockend - start a block */
static void I(blockend)(Env *e) {
if (off > maxoff)
maxoff = off;
START; print("blockend off=%d", off); END;
off = e->offset;
}
/* defaddress - initialize an address */
static void I(defaddress)(Symbol p){
START; print("defaddress "); emitSymRef(p); END;
}
/* defconst - define a constant */
static void I(defconst)(int suffix, int size, Value v) {
START;
print("defconst ");
switch (suffix) {
case I:
print("int.%d ", size);
BEGIN(code);
if (size > sizeof (int))
print("%D", v.i);
else
print("%d", (int)v.i);
END;
break;
case U:
print("unsigned.%d ", size);
BEGIN(code);
if (size > sizeof (unsigned))
print("%U", v.u);
else
print("%u", (unsigned)v.u);
END;
break;
case P: print("void*.%d ", size); BEGIN(code); print("%p", v.p); END; break;
case F: print("float.%d ", size); BEGIN(code); print("%g", (double)v.d); END; break;
default: assert(0);
}
END;
}
/* defstring - emit a string constant */
static void I(defstring)(int len, char *s) {
START; print("defstring ");
BEGIN(code); print("\""); emitString(len, s); print("\""); END;
END;
}
/* defsymbol - define a symbol: initialize p->x */
static void I(defsymbol)(Symbol p) {
if (p->x.name == NULL)
p->x.name = stringd(++uid);
}
/* emit - emit the dags on list p */
static void I(emit)(Node p){
ITEM;
if (!html)
print(" ");
for (; p; p = p->x.next) {
if (p->op == LABEL+V) {
assert(p->syms[0]);
ANCHOR(name,print("%s", p->syms[0]->x.name));
BEGIN(code); print("%s", p->syms[0]->name); END;
END;
print(":");
} else {
int i;
if (p->x.listed) {
BEGIN(strong); print("%d", p->x.inst); END; print("'");
print(" %s", opname(p->op));
} else
print("%d. %s", p->x.inst, opname(p->op));
if (p->count > 1)
print(" count=%d", p->count);
for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
print(" #%d", p->kids[i]->x.inst);
if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
print(" {%t}", p->syms[0]->type);
else
for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) {
print(" ");
if (p->syms[i]->scope == CONSTANTS)
print(p->syms[i]->name);
else
emitSymRef(p->syms[i]);
}
}
NEWLINE;
}
END;
}
/* export - announce p as exported */
static void I(export)(Symbol p) {
START; print("export "); emitSymRef(p); END;
}
/* function - generate code for a function */
static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
int i;
(*IR->defsymbol)(f);
off = 0;
for (i = 0; caller[i] && callee[i]; i++) {
off = roundup(off, caller[i]->type->align);
caller[i]->x.offset = callee[i]->x.offset = off;
off += caller[i]->type->size;
}
if (!html) {
print("function ");
emitSymbol(f);
print(" ncalls=%d\n", ncalls);
for (i = 0; caller[i]; i++)
START; print("caller "); emitSymbol(caller[i]); END;
for (i = 0; callee[i]; i++)
START; print("callee "); emitSymbol(callee[i]); END;
} else {
START;
print("function");
BEGIN(UL);
#define xx(field,code) ITEM; print(#field "="); code; END
xx(f,emitSymbol(f));
xx(ncalls,print("%d", ncalls));
if (caller[0]) {
ITEM; print("caller"); BEGIN(OL);
for (i = 0; caller[i]; i++)
ITEM; emitSymbol(caller[i]); END;
END; END;
ITEM; print("callee"); BEGIN(OL);
for (i = 0; callee[i]; i++)
ITEM; emitSymbol(callee[i]); END;
END; END;
} else {
xx(caller,BEGIN(em); print("empty"); END);
xx(callee,BEGIN(em); print("empty"); END);
}
END;
END;
}
maxoff = off = 0;
gencode(caller, callee);
if (html)
START; print("emitcode"); BEGIN(ul); emitcode(); END; END;
else
emitcode();
START; print("maxoff=%d", maxoff); END;
#undef xx
}
/* visit - generate code for *p */
static int visit(Node p, int n) {
if (p && p->x.inst == 0) {
p->x.inst = ++n;
n = visit(p->kids[0], n);
n = visit(p->kids[1], n);
*tail = p;
tail = &p->x.next;
}
return n;
}
/* gen0 - generate code for the dags on list p */
static Node I(gen)(Node p) {
int n;
Node nodelist;
tail = &nodelist;
for (n = 0; p; p = p->link) {
switch (generic(p->op)) { /* check for valid forest */
case CALL:
assert(IR->wants_dag || p->count == 0);
break;
case ARG:
case ASGN: case JUMP: case LABEL: case RET:
case EQ: case GE: case GT: case LE: case LT: case NE:
assert(p->count == 0);
break;
case INDIR:
assert(IR->wants_dag && p->count > 0);
break;
default:
assert(0);
}
check(p);
p->x.listed = 1;
n = visit(p, n);
}
*tail = 0;
return nodelist;
}
/* global - announce a global */
static void I(global)(Symbol p) {
START; print("global "); emitSymbol(p); END;
}
/* import - import a symbol */
static void I(import)(Symbol p) {
START; print("import "); emitSymRef(p); END;
}
/* local - local variable */
static void I(local)(Symbol p) {
if (p->temporary)
p->name = stringf("t%s", p->name);
(*IR->defsymbol)(p);
off = roundup(off, p->type->align);
p->x.offset = off;
off += p->type->size;
START; print(p->temporary ? "temporary " : "local "); emitSymbol(p); END;
}
/* progbeg - beginning of program */
static void I(progbeg)(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; i++)
if (strcmp(argv[i], "-v") == 0)
verbose++;
else if (strcmp(argv[i], "-html") == 0)
html++;
if (html) {
print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n");
print("<html>");
BEGIN(head);
if (firstfile && *firstfile)
BEGIN(title); emitString(strlen(firstfile), firstfile); END;
print("<link rev=made href=\"mailto:drh@microsoft.com\">\n");
END;
print("<body>\n");
if (firstfile && *firstfile)
BEGIN(h1); emitString(strlen(firstfile), firstfile); END;
BEGIN(P); BEGIN(em);
print("Links lead from uses of identifiers and labels to their definitions.");
END; END;
print("<ul>\n");
START;
print("progbeg");
BEGIN(ol);
for (i = 1; i < argc; i++) {
ITEM;
BEGIN(code); print("\""); emitString(strlen(argv[i]), argv[i]); print("\""); END;
END;
}
END;
END;
}
}
/* progend - end of program */
static void I(progend)(void) {
START; print("progend"); END;
if (html) {
time_t t;
print("</ul>\n");
time(&t);
print("<hr><address>%s</address>\n", ctime(&t));
print("</body></html>\n");
}
}
/* segment - switch to segment s */
static void I(segment)(int s) {
START; print("segment %s", &"text\0bss\0.data\0lit\0.sym\0."[5*s-5]); END;
}
/* space - initialize n bytes of space */
static void I(space)(int n) {
START; print("space %d", n); END;
}
static void I(stabblock)(int brace, int lev, Symbol *p) {}
/* stabend - finalize stab output */
static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {
int i;
if (p)
emitSymRef(p);
print("\n");
if (cpp && sp)
for (i = 0; cpp[i] && sp[i]; i++) {
print("%w.%d: ", cpp[i], cpp[i]->x);
emitSymRef(sp[i]);
print("\n");
}
}
static void I(stabfend)(Symbol p, int lineno) {}
static void I(stabinit)(char *file, int argc, char *argv[]) {}
/* stabline - emit line number information for source coordinate *cp */
static void I(stabline)(Coordinate *cp) {
if (cp->file)
print("%s:", cp->file);
print("%d.%d:\n", cp->y, cp->x);
}
static void I(stabsym)(Symbol p) {}
static void I(stabtype)(Symbol p) {}
Interface symbolicIR = {
{1, 1, 0}, /* char */
{2, 2, 0}, /* short */
{4, 4, 0}, /* int */
{4, 4, 0}, /* long */
{4, 4, 0}, /* long long */
{4, 4, 1}, /* float */
{8, 8, 1}, /* double */
{8, 8, 1}, /* long double */
{4, 4, 0}, /* T* */
{0, 4, 0}, /* struct */
0, /* little_endian */
0, /* mulops_calls */
0, /* wants_callb */
1, /* wants_argb */
1, /* left_to_right */
1, /* wants_dag */
0, /* unsigned_char */
I(address),
I(blockbeg),
I(blockend),
I(defaddress),
I(defconst),
I(defstring),
I(defsymbol),
I(emit),
I(export),
I(function),
I(gen),
I(global),
I(import),
I(local),
I(progbeg),
I(progend),
I(segment),
I(space),
I(stabblock),
I(stabend),
I(stabfend),
I(stabinit),
I(stabline),
I(stabsym),
I(stabtype)
};
Interface symbolic64IR = {
{1, 1, 0}, /* char */
{2, 2, 0}, /* short */
{4, 4, 0}, /* int */
{8, 8, 0}, /* long */
{8, 8, 0}, /* long long */
{4, 4, 1}, /* float */
{8, 8, 1}, /* double */
{8, 8, 1}, /* long double */
{8, 8, 0}, /* T* */
{0, 1, 0}, /* struct */
1, /* little_endian */
0, /* mulops_calls */
0, /* wants_callb */
1, /* wants_argb */
1, /* left_to_right */
1, /* wants_dag */
0, /* unsigned_char */
I(address),
I(blockbeg),
I(blockend),
I(defaddress),
I(defconst),
I(defstring),
I(defsymbol),
I(emit),
I(export),
I(function),
I(gen),
I(global),
I(import),
I(local),
I(progbeg),
I(progend),
I(segment),
I(space),
I(stabblock),
I(stabend),
I(stabfend),
I(stabinit),
I(stabline),
I(stabsym),
I(stabtype)
};

View File

@@ -1,133 +0,0 @@
/*
xx(symbol, value, prec, op, optree, kind, string)
*/
yy(0, 0, 0, 0, 0, 0, 0)
xx(FLOAT, 1, 0, 0, 0, CHAR, "float")
xx(DOUBLE, 2, 0, 0, 0, CHAR, "double")
xx(CHAR, 3, 0, 0, 0, CHAR, "char")
xx(SHORT, 4, 0, 0, 0, CHAR, "short")
xx(INT, 5, 0, 0, 0, CHAR, "int")
xx(UNSIGNED, 6, 0, 0, 0, CHAR, "unsigned")
xx(POINTER, 7, 0, 0, 0, 0, "pointer")
xx(VOID, 8, 0, 0, 0, CHAR, "void")
xx(STRUCT, 9, 0, 0, 0, CHAR, "struct")
xx(UNION, 10, 0, 0, 0, CHAR, "union")
xx(FUNCTION, 11, 0, 0, 0, 0, "function")
xx(ARRAY, 12, 0, 0, 0, 0, "array")
xx(ENUM, 13, 0, 0, 0, CHAR, "enum")
xx(LONG, 14, 0, 0, 0, CHAR, "long")
xx(CONST, 15, 0, 0, 0, CHAR, "const")
xx(VOLATILE, 16, 0, 0, 0, CHAR, "volatile")
yy(0, 17, 0, 0, 0, 0, 0)
yy(0, 18, 0, 0, 0, 0, 0)
yy(0, 19, 0, 0, 0, 0, 0)
yy(0, 20, 0, 0, 0, 0, 0)
yy(0, 21, 0, 0, 0, 0, 0)
yy(0, 22, 0, 0, 0, 0, 0)
yy(0, 23, 0, 0, 0, 0, 0)
yy(0, 24, 0, 0, 0, 0, 0)
yy(0, 25, 0, 0, 0, 0, 0)
yy(0, 26, 0, 0, 0, 0, 0)
yy(0, 27, 0, 0, 0, 0, 0)
yy(0, 28, 0, 0, 0, 0, "long long")
yy(0, 29, 0, 0, 0, 0, 0)
yy(0, 30, 0, 0, 0, 0, 0)
yy(0, 31, 0, 0, 0, 0, "const volatile")
xx(ID, 32, 0, 0, 0, ID, "identifier")
yy(0, 33, 0, 0, 0, ID, "!")
xx(FCON, 34, 0, 0, 0, ID, "floating constant")
xx(ICON, 35, 0, 0, 0, ID, "integer constant")
xx(SCON, 36, 0, 0, 0, ID, "string constant")
yy(0, 37, 13, MOD, bittree,'%', "%")
yy(0, 38, 8, BAND, bittree,ID, "&")
xx(INCR, 39, 0, ADD, addtree,ID, "++")
yy(0, 40, 0, 0, 0, ID, "(")
yy(0, 41, 0, 0, 0, ')', ")")
yy(0, 42, 13, MUL, multree,ID, "*")
yy(0, 43, 12, ADD, addtree,ID, "+")
yy(0, 44, 1, 0, 0, ',', ",")
yy(0, 45, 12, SUB, subtree,ID, "-")
yy(0, 46, 0, 0, 0, '.', ".")
yy(0, 47, 13, DIV, multree,'/', "/")
xx(DECR, 48, 0, SUB, subtree,ID, "--")
xx(DEREF, 49, 0, 0, 0, DEREF, "->")
xx(ANDAND, 50, 5, AND, andtree,ANDAND, "&&")
xx(OROR, 51, 4, OR, andtree,OROR, "||")
xx(LEQ, 52, 10, LE, cmptree,LEQ, "<=")
xx(EQL, 53, 9, EQ, eqtree, EQL, "==")
xx(NEQ, 54, 9, NE, eqtree, NEQ, "!=")
xx(GEQ, 55, 10, GE, cmptree,GEQ, ">=")
xx(RSHIFT, 56, 11, RSH, shtree, RSHIFT, ">>")
xx(LSHIFT, 57, 11, LSH, shtree, LSHIFT, "<<")
yy(0, 58, 0, 0, 0, ':', ":")
yy(0, 59, 0, 0, 0, IF, ";")
yy(0, 60, 10, LT, cmptree,'<', "<")
yy(0, 61, 2, ASGN, asgntree,'=', "=")
yy(0, 62, 10, GT, cmptree,'>', ">")
yy(0, 63, 0, 0, 0, '?', "?")
xx(ELLIPSIS, 64, 0, 0, 0, ELLIPSIS,"...")
xx(SIZEOF, 65, 0, 0, 0, ID, "sizeof")
yy(0, 66, 0, 0, 0, 0, 0)
xx(AUTO, 67, 0, 0, 0, STATIC, "auto")
xx(BREAK, 68, 0, 0, 0, IF, "break")
xx(CASE, 69, 0, 0, 0, IF, "case")
xx(CONTINUE, 70, 0, 0, 0, IF, "continue")
xx(DEFAULT, 71, 0, 0, 0, IF, "default")
xx(DO, 72, 0, 0, 0, IF, "do")
xx(ELSE, 73, 0, 0, 0, IF, "else")
xx(EXTERN, 74, 0, 0, 0, STATIC, "extern")
xx(FOR, 75, 0, 0, 0, IF, "for")
xx(GOTO, 76, 0, 0, 0, IF, "goto")
xx(IF, 77, 0, 0, 0, IF, "if")
xx(REGISTER, 78, 0, 0, 0, STATIC, "register")
xx(RETURN, 79, 0, 0, 0, IF, "return")
xx(SIGNED, 80, 0, 0, 0, CHAR, "signed")
xx(STATIC, 81, 0, 0, 0, STATIC, "static")
xx(SWITCH, 82, 0, 0, 0, IF, "switch")
xx(TYPEDEF, 83, 0, 0, 0, STATIC, "typedef")
xx(WHILE, 84, 0, 0, 0, IF, "while")
xx(TYPECODE, 85, 0, 0, 0, ID, "__typecode")
xx(FIRSTARG, 86, 0, 0, 0, ID, "__firstarg")
yy(0, 87, 0, 0, 0, 0, 0)
yy(0, 88, 0, 0, 0, 0, 0)
yy(0, 89, 0, 0, 0, 0, 0)
yy(0, 90, 0, 0, 0, 0, 0)
yy(0, 91, 0, 0, 0, '[', "[")
yy(0, 92, 0, 0, 0, 0, 0)
yy(0, 93, 0, 0, 0, ']', "]")
yy(0, 94, 7, BXOR, bittree,'^', "^")
yy(0, 95, 0, 0, 0, 0, 0)
yy(0, 96, 0, 0, 0, 0, 0)
yy(0, 97, 0, 0, 0, 0, 0)
yy(0, 98, 0, 0, 0, 0, 0)
yy(0, 99, 0, 0, 0, 0, 0)
yy(0, 100, 0, 0, 0, 0, 0)
yy(0, 101, 0, 0, 0, 0, 0)
yy(0, 102, 0, 0, 0, 0, 0)
yy(0, 103, 0, 0, 0, 0, 0)
yy(0, 104, 0, 0, 0, 0, 0)
yy(0, 105, 0, 0, 0, 0, 0)
yy(0, 106, 0, 0, 0, 0, 0)
yy(0, 107, 0, 0, 0, 0, 0)
yy(0, 108, 0, 0, 0, 0, 0)
yy(0, 109, 0, 0, 0, 0, 0)
yy(0, 110, 0, 0, 0, 0, 0)
yy(0, 111, 0, 0, 0, 0, 0)
yy(0, 112, 0, 0, 0, 0, 0)
yy(0, 113, 0, 0, 0, 0, 0)
yy(0, 114, 0, 0, 0, 0, 0)
yy(0, 115, 0, 0, 0, 0, 0)
yy(0, 116, 0, 0, 0, 0, 0)
yy(0, 117, 0, 0, 0, 0, 0)
yy(0, 118, 0, 0, 0, 0, 0)
yy(0, 119, 0, 0, 0, 0, 0)
yy(0, 120, 0, 0, 0, 0, 0)
yy(0, 121, 0, 0, 0, 0, 0)
yy(0, 122, 0, 0, 0, 0, 0)
yy(0, 123, 0, 0, 0, IF, "{")
yy(0, 124, 6, BOR, bittree,'|', "|")
yy(0, 125, 0, 0, 0, '}', "}")
yy(0, 126, 0, BCOM, 0, ID, "~")
xx(EOI, 127, 0, 0, 0, EOI, "end of input")
#undef xx
#undef yy

View File

@@ -1,181 +0,0 @@
#include "c.h"
static char *fmt, *fp, *fmtend; /* format string, current & limit pointer */
static Tree args; /* printf arguments */
static Symbol frameno; /* local holding frame number */
/* appendstr - append str to the evolving format string, expanding it if necessary */
static void appendstr(char *str) {
do
if (fp == fmtend) {
if (fp) {
char *s = allocate(2*(fmtend - fmt), FUNC);
strncpy(s, fmt, fmtend - fmt);
fp = s + (fmtend - fmt);
fmtend = s + 2*(fmtend - fmt);
fmt = s;
} else {
fp = fmt = allocate(80, FUNC);
fmtend = fmt + 80;
}
}
while ((*fp++ = *str++) != 0);
fp--;
}
/* tracevalue - append format and argument to print the value of e */
static void tracevalue(Tree e, int lev) {
Type ty = unqual(e->type);
switch (ty->op) {
case INT:
if (ty == chartype || ty == signedchar)
appendstr("'\\x%02x'");
else if (ty == longtype)
appendstr("0x%ld");
else
appendstr("0x%d");
break;
case UNSIGNED:
if (ty == chartype || ty == unsignedchar)
appendstr("'\\x%02x'");
else if (ty == unsignedlong)
appendstr("0x%lx");
else
appendstr("0x%x");
break;
case FLOAT:
if (ty == longdouble)
appendstr("%Lg");
else
appendstr("%g");
break;
case POINTER:
if (unqual(ty->type) == chartype
|| unqual(ty->type) == signedchar
|| unqual(ty->type) == unsignedchar) {
static Symbol null;
if (null == NULL)
null = mkstr("(null)");
tracevalue(cast(e, unsignedtype), lev + 1);
appendstr(" \"%.30s\"");
e = condtree(e, e, pointer(idtree(null->u.c.loc)));
} else {
appendstr("("); appendstr(typestring(ty, "")); appendstr(")0x%x");
}
break;
case STRUCT: {
Field q;
appendstr("("); appendstr(typestring(ty, "")); appendstr("){");
for (q = ty->u.sym->u.s.flist; q; q = q->link) {
appendstr(q->name); appendstr("=");
tracevalue(field(addrof(e), q->name), lev + 1);
if (q->link)
appendstr(",");
}
appendstr("}");
return;
}
case UNION:
appendstr("("); appendstr(typestring(ty, "")); appendstr("){...}");
return;
case ARRAY:
if (lev && ty->type->size > 0) {
int i;
e = pointer(e);
appendstr("{");
for (i = 0; i < ty->size/ty->type->size; i++) {
Tree p = (*optree['+'])(ADD, e, consttree(i, inttype));
if (isptr(p->type) && isarray(p->type->type))
p = retype(p, p->type->type);
else
p = rvalue(p);
if (i)
appendstr(",");
tracevalue(p, lev + 1);
}
appendstr("}");
} else
appendstr(typestring(ty, ""));
return;
default:
assert(0);
}
e = cast(e, promote(ty));
args = tree(mkop(ARG,e->type), e->type, e, args);
}
/* tracefinis - complete & generate the trace call to print */
static void tracefinis(Symbol printer) {
Tree *ap;
Symbol p;
*fp = 0;
p = mkstr(string(fmt));
for (ap = &args; *ap; ap = &(*ap)->kids[1])
;
*ap = tree(ARG+P, charptype, pointer(idtree(p->u.c.loc)), 0);
walk(calltree(pointer(idtree(printer)), freturn(printer->type), args, NULL), 0, 0);
args = 0;
fp = fmtend = 0;
}
/* tracecall - generate code to trace entry to f */
static void tracecall(Symbol printer, Symbol f) {
int i;
Symbol counter = genident(STATIC, inttype, GLOBAL);
defglobal(counter, BSS);
(*IR->space)(counter->type->size);
frameno = genident(AUTO, inttype, level);
addlocal(frameno);
appendstr(f->name); appendstr("#");
tracevalue(asgn(frameno, incr(INCR, idtree(counter), consttree(1, inttype))), 0);
appendstr("(");
for (i = 0; f->u.f.callee[i]; i++) {
if (i)
appendstr(",");
appendstr(f->u.f.callee[i]->name); appendstr("=");
tracevalue(idtree(f->u.f.callee[i]), 0);
}
if (variadic(f->type))
appendstr(",...");
appendstr(") called\n");
tracefinis(printer);
}
/* tracereturn - generate code to trace return e */
static void tracereturn(Symbol printer, Symbol f, Tree e) {
appendstr(f->name); appendstr("#");
tracevalue(idtree(frameno), 0);
appendstr(" returned");
if (freturn(f->type) != voidtype && e) {
appendstr(" ");
tracevalue(e, 0);
}
appendstr("\n");
tracefinis(printer);
}
/* trace_init - initialize for tracing */
void trace_init(int argc, char *argv[]) {
int i;
static int inited;
if (inited)
return;
inited = 1;
type_init(argc, argv);
if (IR)
for (i = 1; i < argc; i++)
if (strncmp(argv[i], "-t", 2) == 0 && strchr(argv[i], '=') == NULL) {
Symbol printer = mksymbol(EXTERN,
argv[i][2] ? &argv[i][2] : "printf",
ftype(inttype, ptr(qual(CONST, chartype))));
printer->defined = 0;
attach((Apply)tracecall, printer, &events.entry);
attach((Apply)tracereturn, printer, &events.returns);
break;
}
}

View File

@@ -1,223 +0,0 @@
#include "c.h"
int where = STMT;
static int warn;
static int nid = 1; /* identifies trees & nodes in debugging output */
static struct nodeid {
int printed;
Tree node;
} ids[500]; /* if ids[i].node == p, then p's id is i */
static void printtree1(Tree, int, int);
Tree tree(int op, Type type, Tree left, Tree right) {
Tree p;
NEW0(p, where);
p->op = op;
p->type = type;
p->kids[0] = left;
p->kids[1] = right;
return p;
}
Tree texpr(Tree (*f)(int), int tok, int a) {
int save = where;
Tree p;
where = a;
p = (*f)(tok);
where = save;
return p;
}
static Tree root1(Tree p) {
if (p == NULL)
return p;
if (p->type == voidtype)
warn++;
switch (generic(p->op)) {
case COND: {
Tree q = p->kids[1];
assert(q && q->op == RIGHT);
if (p->u.sym && q->kids[0] && generic(q->kids[0]->op) == ASGN)
q->kids[0] = root1(q->kids[0]->kids[1]);
else
q->kids[0] = root1(q->kids[0]);
if (p->u.sym && q->kids[1] && generic(q->kids[1]->op) == ASGN)
q->kids[1] = root1(q->kids[1]->kids[1]);
else
q->kids[1] = root1(q->kids[1]);
p->u.sym = 0;
if (q->kids[0] == 0 && q->kids[1] == 0)
p = root1(p->kids[0]);
}
break;
case AND: case OR:
if ((p->kids[1] = root1(p->kids[1])) == 0)
p = root1(p->kids[0]);
break;
case NOT:
if (warn++ == 0)
warning("expression with no effect elided\n");
return root1(p->kids[0]);
case RIGHT:
if (p->kids[1] == 0)
return root1(p->kids[0]);
if (p->kids[0] && p->kids[0]->op == CALL+B
&& p->kids[1] && p->kids[1]->op == INDIR+B)
/* avoid premature release of the CALL+B temporary */
return p->kids[0];
if (p->kids[0] && p->kids[0]->op == RIGHT
&& p->kids[1] == p->kids[0]->kids[0])
/* de-construct e++ construction */
return p->kids[0]->kids[1];
p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1]));
return p->kids[0] || p->kids[1] ? p : (Tree)0;
case EQ: case NE: case GT: case GE: case LE: case LT:
case ADD: case SUB: case MUL: case DIV: case MOD:
case LSH: case RSH: case BAND: case BOR: case BXOR:
if (warn++ == 0)
warning("expression with no effect elided\n");
p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1]));
return p->kids[0] || p->kids[1] ? p : (Tree)0;
case INDIR:
if (p->type->size == 0 && unqual(p->type) != voidtype)
warning("reference to `%t' elided\n", p->type);
if (isptr(p->kids[0]->type) && isvolatile(p->kids[0]->type->type))
warning("reference to `volatile %t' elided\n", p->type);
/* fall thru */
case CVI: case CVF: case CVU: case CVP:
case NEG: case BCOM: case FIELD:
if (warn++ == 0)
warning("expression with no effect elided\n");
return root1(p->kids[0]);
case ADDRL: case ADDRG: case ADDRF: case CNST:
if (needconst)
return p;
if (warn++ == 0)
warning("expression with no effect elided\n");
return NULL;
case ARG: case ASGN: case CALL: case JUMP: case LABEL:
break;
default: assert(0);
}
return p;
}
Tree root(Tree p) {
warn = 0;
return root1(p);
}
char *opname(int op) {
static char *opnames[] = {
"",
"CNST",
"ARG",
"ASGN",
"INDIR",
"CVC",
"CVD",
"CVF",
"CVI",
"CVP",
"CVS",
"CVU",
"NEG",
"CALL",
"*LOAD*",
"RET",
"ADDRG",
"ADDRF",
"ADDRL",
"ADD",
"SUB",
"LSH",
"MOD",
"RSH",
"BAND",
"BCOM",
"BOR",
"BXOR",
"DIV",
"MUL",
"EQ",
"GE",
"GT",
"LE",
"LT",
"NE",
"JUMP",
"LABEL",
"AND",
"NOT",
"OR",
"COND",
"RIGHT",
"FIELD"
}, *suffixes[] = {
"0", "F", "D", "C", "S", "I", "U", "P", "V", "B",
"10","11","12","13","14","15"
};
if (generic(op) >= AND && generic(op) <= FIELD && opsize(op) == 0)
return opnames[opindex(op)];
return stringf("%s%s%s",
opindex(op) > 0 && opindex(op) < NELEMS(opnames) ?
opnames[opindex(op)] : stringd(opindex(op)),
suffixes[optype(op)], opsize(op) > 0 ? stringd(opsize(op)) : "");
}
int nodeid(Tree p) {
int i = 1;
ids[nid].node = p;
while (ids[i].node != p)
i++;
if (i == nid)
ids[nid++].printed = 0;
return i;
}
/* printed - return pointer to ids[id].printed */
int *printed(int id) {
if (id)
return &ids[id].printed;
nid = 1;
return 0;
}
/* printtree - print tree p on fd */
void printtree(Tree p, int fd) {
(void)printed(0);
printtree1(p, fd, 1);
}
/* printtree1 - recursively print tree p */
static void printtree1(Tree p, int fd, int lev) {
FILE *f = fd == 1 ? stdout : stderr;
int i;
static char blanks[] = " ";
if (p == 0 || *printed(i = nodeid(p)))
return;
fprint(f, "#%d%S%S", i, blanks, i < 10 ? 2 : i < 100 ? 1 : 0, blanks, lev);
fprint(f, "%s %t", opname(p->op), p->type);
*printed(i) = 1;
for (i = 0; i < NELEMS(p->kids); i++)
if (p->kids[i])
fprint(f, " #%d", nodeid(p->kids[i]));
if (p->op == FIELD && p->u.field)
fprint(f, " %s %d..%d", p->u.field->name,
fieldsize(p->u.field) + fieldright(p->u.field), fieldright(p->u.field));
else if (generic(p->op) == CNST)
fprint(f, " %s", vtoa(p->type, p->u.v));
else if (p->u.sym)
fprint(f, " %s", p->u.sym->name);
if (p->node)
fprint(f, " node=%p", p->node);
fprint(f, "\n");
for (i = 0; i < NELEMS(p->kids); i++)
printtree1(p->kids[i], fd, lev + 1);
}

View File

@@ -1,748 +0,0 @@
#include "c.h"
#include <float.h>
static Field isfield(const char *, Field);
static Type type(int, Type, int, int, void *);
static struct entry {
struct type type;
struct entry *link;
} *typetable[128];
static int maxlevel;
static Symbol pointersym;
Type chartype; /* char */
Type doubletype; /* double */
Type floattype; /* float */
Type inttype; /* signed int */
Type longdouble; /* long double */
Type longtype; /* long */
Type longlong; /* long long */
Type shorttype; /* signed short int */
Type signedchar; /* signed char */
Type unsignedchar; /* unsigned char */
Type unsignedlong; /* unsigned long int */
Type unsignedlonglong; /* unsigned long long int */
Type unsignedshort; /* unsigned short int */
Type unsignedtype; /* unsigned int */
Type funcptype; /* void (*)() */
Type charptype; /* char* */
Type voidptype; /* void* */
Type voidtype; /* basic types: void */
Type unsignedptr; /* unsigned type to hold void* */
Type signedptr; /* signed type to hold void* */
Type widechar; /* unsigned type that represents wchar_t */
static Type xxinit(int op, char *name, Metrics m) {
Symbol p = install(string(name), &types, GLOBAL, PERM);
Type ty = type(op, 0, m.size, m.align, p);
assert(ty->align == 0 || ty->size%ty->align == 0);
p->type = ty;
p->addressed = m.outofline;
switch (ty->op) {
case INT:
p->u.limits.max.i = ones(8*ty->size)>>1;
p->u.limits.min.i = -p->u.limits.max.i - 1;
break;
case UNSIGNED:
p->u.limits.max.u = ones(8*ty->size);
p->u.limits.min.u = 0;
break;
case FLOAT:
if (ty->size == sizeof (float))
p->u.limits.max.d = FLT_MAX;
else if (ty->size == sizeof (double))
p->u.limits.max.d = DBL_MAX;
else
p->u.limits.max.d = LDBL_MAX;
p->u.limits.min.d = -p->u.limits.max.d;
break;
default: assert(0);
}
return ty;
}
static Type type(int op, Type ty, int size, int align, void *sym) {
unsigned h = (op^((unsigned long)ty>>3))
&(NELEMS(typetable)-1);
struct entry *tn;
if (op != FUNCTION && (op != ARRAY || size > 0))
for (tn = typetable[h]; tn; tn = tn->link)
if (tn->type.op == op && tn->type.type == ty
&& tn->type.size == size && tn->type.align == align
&& tn->type.u.sym == sym)
return &tn->type;
NEW0(tn, PERM);
tn->type.op = op;
tn->type.type = ty;
tn->type.size = size;
tn->type.align = align;
tn->type.u.sym = sym;
tn->link = typetable[h];
typetable[h] = tn;
return &tn->type;
}
void type_init(int argc, char *argv[]) {
static int inited;
int i;
if (inited)
return;
inited = 1;
if (!IR)
return;
for (i = 1; i < argc; i++) {
int size, align, outofline;
if (strncmp(argv[i], "-unsigned_char=", 15) == 0)
IR->unsigned_char = argv[i][15] - '0';
#define xx(name) \
else if (sscanf(argv[i], "-" #name "=%d,%d,%d", &size, &align, &outofline) == 3) { \
IR->name.size = size; IR->name.align = align; \
IR->name.outofline = outofline; }
xx(charmetric)
xx(shortmetric)
xx(intmetric)
xx(longmetric)
xx(longlongmetric)
xx(floatmetric)
xx(doublemetric)
xx(longdoublemetric)
xx(ptrmetric)
xx(structmetric)
#undef xx
}
#define xx(v,name,op,metrics) v=xxinit(op,name,IR->metrics)
xx(chartype, "char", IR->unsigned_char ? UNSIGNED : INT,charmetric);
xx(doubletype, "double", FLOAT, doublemetric);
xx(floattype, "float", FLOAT, floatmetric);
xx(inttype, "int", INT, intmetric);
xx(longdouble, "long double", FLOAT, longdoublemetric);
xx(longtype, "long int", INT, longmetric);
xx(longlong, "long long int", INT, longlongmetric);
xx(shorttype, "short", INT, shortmetric);
xx(signedchar, "signed char", INT, charmetric);
xx(unsignedchar, "unsigned char", UNSIGNED,charmetric);
xx(unsignedlong, "unsigned long", UNSIGNED,longmetric);
xx(unsignedshort, "unsigned short", UNSIGNED,shortmetric);
xx(unsignedtype, "unsigned int", UNSIGNED,intmetric);
xx(unsignedlonglong,"unsigned long long",UNSIGNED,longlongmetric);
#undef xx
{
Symbol p;
p = install(string("void"), &types, GLOBAL, PERM);
voidtype = type(VOID, NULL, 0, 0, p);
p->type = voidtype;
}
pointersym = install(string("T*"), &types, GLOBAL, PERM);
pointersym->addressed = IR->ptrmetric.outofline;
pointersym->u.limits.max.p = (void*)ones(8*IR->ptrmetric.size);
pointersym->u.limits.min.p = 0;
voidptype = ptr(voidtype);
funcptype = ptr(func(voidtype, NULL, 1));
charptype = ptr(chartype);
#define xx(v,t) if (v==NULL && t->size==voidptype->size && t->align==voidptype->align) v=t
xx(unsignedptr,unsignedshort);
xx(unsignedptr,unsignedtype);
xx(unsignedptr,unsignedlong);
xx(unsignedptr,unsignedlonglong);
if (unsignedptr == NULL)
unsignedptr = type(UNSIGNED, NULL, voidptype->size, voidptype->align, voidptype->u.sym);
xx(signedptr,shorttype);
xx(signedptr,inttype);
xx(signedptr,longtype);
xx(signedptr,longlong);
if (signedptr == NULL)
signedptr = type(INT, NULL, voidptype->size, voidptype->align, voidptype->u.sym);
#undef xx
widechar = unsignedshort;
for (i = 0; i < argc; i++) {
#define xx(name,type) \
if (strcmp(argv[i], "-wchar_t=" #name) == 0) \
widechar = type;
xx(unsigned_char,unsignedchar)
xx(unsigned_int,unsignedtype)
xx(unsigned_short,unsignedshort)
}
#undef xx
}
void rmtypes(int lev) {
if (maxlevel >= lev) {
int i;
maxlevel = 0;
for (i = 0; i < NELEMS(typetable); i++) {
struct entry *tn, **tq = &typetable[i];
while ((tn = *tq) != NULL)
if (tn->type.op == FUNCTION)
tq = &tn->link;
else if (tn->type.u.sym && tn->type.u.sym->scope >= lev)
*tq = tn->link;
else {
if (tn->type.u.sym && tn->type.u.sym->scope > maxlevel)
maxlevel = tn->type.u.sym->scope;
tq = &tn->link;
}
}
}
}
Type ptr(Type ty) {
return type(POINTER, ty, IR->ptrmetric.size,
IR->ptrmetric.align, pointersym);
}
Type deref(Type ty) {
if (isptr(ty))
ty = ty->type;
else
error("type error: %s\n", "pointer expected");
return isenum(ty) ? unqual(ty)->type : ty;
}
Type array(Type ty, int n, int a) {
assert(ty);
if (isfunc(ty)) {
error("illegal type `array of %t'\n", ty);
return array(inttype, n, 0);
}
if (isarray(ty) && ty->size == 0)
error("missing array size\n");
if (ty->size == 0) {
if (unqual(ty) == voidtype)
error("illegal type `array of %t'\n", ty);
else if (Aflag >= 2)
warning("declaring type array of %t' is undefined\n", ty);
} else if (n > INT_MAX/ty->size) {
error("size of `array of %t' exceeds %d bytes\n",
ty, INT_MAX);
n = 1;
}
return type(ARRAY, ty, n*ty->size,
a ? a : ty->align, NULL);
}
Type atop(Type ty) {
if (isarray(ty))
return ptr(ty->type);
error("type error: %s\n", "array expected");
return ptr(ty);
}
Type qual(int op, Type ty) {
if (isarray(ty))
ty = type(ARRAY, qual(op, ty->type), ty->size,
ty->align, NULL);
else if (isfunc(ty))
warning("qualified function type ignored\n");
else if ((isconst(ty) && op == CONST)
|| (isvolatile(ty) && op == VOLATILE))
error("illegal type `%k %t'\n", op, ty);
else {
if (isqual(ty)) {
op += ty->op;
ty = ty->type;
}
ty = type(op, ty, ty->size, ty->align, NULL);
}
return ty;
}
Type func(Type ty, Type *proto, int style) {
if (ty && (isarray(ty) || isfunc(ty)))
error("illegal return type `%t'\n", ty);
ty = type(FUNCTION, ty, 0, 0, NULL);
ty->u.f.proto = proto;
ty->u.f.oldstyle = style;
return ty;
}
Type freturn(Type ty) {
if (isfunc(ty))
return ty->type;
error("type error: %s\n", "function expected");
return inttype;
}
int variadic(Type ty) {
if (isfunc(ty) && ty->u.f.proto) {
int i;
for (i = 0; ty->u.f.proto[i]; i++)
;
return i > 1 && ty->u.f.proto[i-1] == voidtype;
}
return 0;
}
Type newstruct(int op, char *tag) {
Symbol p;
assert(tag);
if (*tag == 0)
tag = stringd(genlabel(1));
else
if ((p = lookup(tag, types)) != NULL && (p->scope == level
|| (p->scope == PARAM && level == PARAM+1))) {
if (p->type->op == op && !p->defined)
return p->type;
error("redefinition of `%s' previously defined at %w\n",
p->name, &p->src);
}
p = install(tag, &types, level, PERM);
p->type = type(op, NULL, 0, 0, p);
if (p->scope > maxlevel)
maxlevel = p->scope;
p->src = src;
return p->type;
}
Field newfield(char *name, Type ty, Type fty) {
Field p, *q = &ty->u.sym->u.s.flist;
if (name == NULL)
name = stringd(genlabel(1));
for (p = *q; p; q = &p->link, p = *q)
if (p->name == name)
error("duplicate field name `%s' in `%t'\n",
name, ty);
NEW0(p, PERM);
*q = p;
p->name = name;
p->type = fty;
if (xref) { /* omit */
if (ty->u.sym->u.s.ftab == NULL) /* omit */
ty->u.sym->u.s.ftab = table(NULL, level); /* omit */
install(name, &ty->u.sym->u.s.ftab, 0, PERM)->src = src;/* omit */
} /* omit */
return p;
}
int eqtype(Type ty1, Type ty2, int ret) {
if (ty1 == ty2)
return 1;
if (ty1->op != ty2->op)
return 0;
switch (ty1->op) {
case ENUM: case UNION: case STRUCT:
case UNSIGNED: case INT: case FLOAT:
return 0;
case POINTER: return eqtype(ty1->type, ty2->type, 1);
case VOLATILE: case CONST+VOLATILE:
case CONST: return eqtype(ty1->type, ty2->type, 1);
case ARRAY: if (eqtype(ty1->type, ty2->type, 1)) {
if (ty1->size == ty2->size)
return 1;
if (ty1->size == 0 || ty2->size == 0)
return ret;
}
return 0;
case FUNCTION: if (eqtype(ty1->type, ty2->type, 1)) {
Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto;
if (p1 == p2)
return 1;
if (p1 && p2) {
for ( ; *p1 && *p2; p1++, p2++)
if (eqtype(unqual(*p1), unqual(*p2), 1) == 0)
return 0;
if (*p1 == NULL && *p2 == NULL)
return 1;
} else {
if (variadic(p1 ? ty1 : ty2))
return 0;
if (p1 == NULL)
p1 = p2;
for ( ; *p1; p1++) {
Type ty = unqual(*p1);
if (promote(ty) != (isenum(ty) ? ty->type : ty))
return 0;
}
return 1;
}
}
return 0;
}
assert(0); return 0;
}
Type promote(Type ty) {
ty = unqual(ty);
switch (ty->op) {
case ENUM:
return inttype;
case INT:
if (ty->size < inttype->size)
return inttype;
break;
case UNSIGNED:
if (ty->size < inttype->size)
return inttype;
if (ty->size < unsignedtype->size)
return unsignedtype;
break;
case FLOAT:
if (ty->size < doubletype->size)
return doubletype;
}
return ty;
}
Type signedint(Type ty) {
if (ty->op == INT)
return ty;
assert(ty->op == UNSIGNED);
#define xx(t) if (ty->size == t->size) return t
xx(inttype);
xx(longtype);
xx(longlong);
#undef xx
assert(0); return NULL;
}
Type compose(Type ty1, Type ty2) {
if (ty1 == ty2)
return ty1;
assert(ty1->op == ty2->op);
switch (ty1->op) {
case POINTER:
return ptr(compose(ty1->type, ty2->type));
case CONST+VOLATILE:
return qual(CONST, qual(VOLATILE,
compose(ty1->type, ty2->type)));
case CONST: case VOLATILE:
return qual(ty1->op, compose(ty1->type, ty2->type));
case ARRAY: { Type ty = compose(ty1->type, ty2->type);
if (ty1->size && ((ty1->type->size && ty2->size == 0) || ty1->size == ty2->size))
return array(ty, ty1->size/ty1->type->size, ty1->align);
if (ty2->size && ty2->type->size && ty1->size == 0)
return array(ty, ty2->size/ty2->type->size, ty2->align);
return array(ty, 0, 0); }
case FUNCTION: { Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto;
Type ty = compose(ty1->type, ty2->type);
List tlist = NULL;
if (p1 == NULL && p2 == NULL)
return func(ty, NULL, 1);
if (p1 && p2 == NULL)
return func(ty, p1, ty1->u.f.oldstyle);
if (p2 && p1 == NULL)
return func(ty, p2, ty2->u.f.oldstyle);
for ( ; *p1 && *p2; p1++, p2++) {
Type ty = compose(unqual(*p1), unqual(*p2));
if (isconst(*p1) || isconst(*p2))
ty = qual(CONST, ty);
if (isvolatile(*p1) || isvolatile(*p2))
ty = qual(VOLATILE, ty);
tlist = append(ty, tlist);
}
assert(*p1 == NULL && *p2 == NULL);
return func(ty, ltov(&tlist, PERM), 0); }
}
assert(0); return NULL;
}
int ttob(Type ty) {
switch (ty->op) {
case CONST: case VOLATILE: case CONST+VOLATILE:
return ttob(ty->type);
case VOID: case INT: case UNSIGNED: case FLOAT:
return ty->op + sizeop(ty->size);
case POINTER:
return POINTER + sizeop(voidptype->size);
case FUNCTION:
return POINTER + sizeop(funcptype->size);
case ARRAY: case STRUCT: case UNION:
return STRUCT;
case ENUM:
return INT + sizeop(inttype->size);
}
assert(0); return INT;
}
Type btot(int op, int size) {
#define xx(ty) if (size == (ty)->size) return ty;
switch (optype(op)) {
case F:
xx(floattype);
xx(doubletype);
xx(longdouble);
assert(0); return 0;
case I:
if (chartype->op == INT)
xx(chartype);
xx(signedchar);
xx(shorttype);
xx(inttype);
xx(longtype);
xx(longlong);
assert(0); return 0;
case U:
if (chartype->op == UNSIGNED)
xx(chartype);
xx(unsignedchar);
xx(unsignedshort);
xx(unsignedtype);
xx(unsignedlong);
xx(unsignedlonglong);
assert(0); return 0;
case P:
xx(voidptype);
xx(funcptype);
assert(0); return 0;
}
#undef xx
assert(0); return 0;
}
int hasproto(Type ty) {
if (ty == 0)
return 1;
switch (ty->op) {
case CONST: case VOLATILE: case CONST+VOLATILE: case POINTER:
case ARRAY:
return hasproto(ty->type);
case FUNCTION:
return hasproto(ty->type) && ty->u.f.proto;
case STRUCT: case UNION:
case VOID: case FLOAT: case ENUM: case INT: case UNSIGNED:
return 1;
}
assert(0); return 0;
}
/* fieldlist - construct a flat list of fields in type ty */
Field fieldlist(Type ty) {
return ty->u.sym->u.s.flist;
}
/* fieldref - find field name of type ty, return entry */
Field fieldref(const char *name, Type ty) {
Field p = isfield(name, unqual(ty)->u.sym->u.s.flist);
if (p && xref) {
Symbol q;
assert(unqual(ty)->u.sym->u.s.ftab);
q = lookup(name, unqual(ty)->u.sym->u.s.ftab);
assert(q);
use(q, src);
}
return p;
}
/* ftype - return a function type for rty function (ty,...)' */
Type ftype(Type rty, Type ty) {
List list = append(ty, NULL);
list = append(voidtype, list);
return func(rty, ltov(&list, PERM), 0);
}
/* isfield - if name is a field in flist, return pointer to the field structure */
static Field isfield(const char *name, Field flist) {
for ( ; flist; flist = flist->link)
if (flist->name == name)
break;
return flist;
}
/* outtype - output type ty */
void outtype(Type ty, FILE *f) {
switch (ty->op) {
case CONST+VOLATILE: case CONST: case VOLATILE:
fprint(f, "%k %t", ty->op, ty->type);
break;
case STRUCT: case UNION: case ENUM:
assert(ty->u.sym);
if (ty->size == 0)
fprint(f, "incomplete ");
assert(ty->u.sym->name);
if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') {
Symbol p = findtype(ty);
if (p == 0)
fprint(f, "%k defined at %w", ty->op, &ty->u.sym->src);
else
fprint(f, p->name);
} else {
fprint(f, "%k %s", ty->op, ty->u.sym->name);
if (ty->size == 0)
fprint(f, " defined at %w", &ty->u.sym->src);
}
break;
case VOID: case FLOAT: case INT: case UNSIGNED:
fprint(f, ty->u.sym->name);
break;
case POINTER:
fprint(f, "pointer to %t", ty->type);
break;
case FUNCTION:
fprint(f, "%t function", ty->type);
if (ty->u.f.proto && ty->u.f.proto[0]) {
int i;
fprint(f, "(%t", ty->u.f.proto[0]);
for (i = 1; ty->u.f.proto[i]; i++)
if (ty->u.f.proto[i] == voidtype)
fprint(f, ",...");
else
fprint(f, ",%t", ty->u.f.proto[i]);
fprint(f, ")");
} else if (ty->u.f.proto && ty->u.f.proto[0] == 0)
fprint(f, "(void)");
break;
case ARRAY:
if (ty->size > 0 && ty->type && ty->type->size > 0) {
fprint(f, "array %d", ty->size/ty->type->size);
while (ty->type && isarray(ty->type) && ty->type->type->size > 0) {
ty = ty->type;
fprint(f, ",%d", ty->size/ty->type->size);
}
} else
fprint(f, "incomplete array");
if (ty->type)
fprint(f, " of %t", ty->type);
break;
default: assert(0);
}
}
/* printdecl - output a C declaration for symbol p of type ty */
void printdecl(Symbol p, Type ty) {
switch (p->sclass) {
case AUTO:
fprint(stderr, "%s;\n", typestring(ty, p->name));
break;
case STATIC: case EXTERN:
fprint(stderr, "%k %s;\n", p->sclass, typestring(ty, p->name));
break;
case TYPEDEF: case ENUM:
break;
default: assert(0);
}
}
/* printproto - output a prototype declaration for function p */
void printproto(Symbol p, Symbol callee[]) {
if (p->type->u.f.proto)
printdecl(p, p->type);
else {
int i;
List list = 0;
if (callee[0] == 0)
list = append(voidtype, list);
else
for (i = 0; callee[i]; i++)
list = append(callee[i]->type, list);
printdecl(p, func(freturn(p->type), ltov(&list, PERM), 0));
}
}
/* prtype - print details of type ty on f with given indent */
static void prtype(Type ty, FILE *f, int indent, unsigned mark) {
switch (ty->op) {
default:
fprint(f, "(%d %d %d [%p])", ty->op, ty->size, ty->align, ty->u.sym);
break;
case FLOAT: case INT: case UNSIGNED: case VOID:
fprint(f, "(%k %d %d [\"%s\"])", ty->op, ty->size, ty->align, ty->u.sym->name);
break;
case CONST+VOLATILE: case CONST: case VOLATILE: case POINTER: case ARRAY:
fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align);
prtype(ty->type, f, indent+1, mark);
fprint(f, ")");
break;
case STRUCT: case UNION:
fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name);
if (ty->x.marked != mark) {
Field p;
ty->x.marked = mark;
for (p = ty->u.sym->u.s.flist; p; p = p->link) {
fprint(f, "\n%I", indent+1);
prtype(p->type, f, indent+1, mark);
fprint(f, " %s@%d", p->name, p->offset);
if (p->lsb)
fprint(f, ":%d..%d",
fieldsize(p) + fieldright(p), fieldright(p));
}
fprint(f, "\n%I", indent);
}
fprint(f, ")");
break;
case ENUM:
fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name);
if (ty->x.marked != mark) {
int i;
Symbol *p = ty->u.sym->u.idlist;
ty->x.marked = mark;
for (i = 0; p[i] != NULL; i++)
fprint(f, "%I%s=%d\n", indent+1, p[i]->name, p[i]->u.value);
}
fprint(f, ")");
break;
case FUNCTION:
fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align);
prtype(ty->type, f, indent+1, mark);
if (ty->u.f.proto) {
int i;
fprint(f, "\n%I{", indent+1);
for (i = 0; ty->u.f.proto[i]; i++) {
if (i > 0)
fprint(f, "%I", indent+2);
prtype(ty->u.f.proto[i], f, indent+2, mark);
fprint(f, "\n");
}
fprint(f, "%I}", indent+1);
}
fprint(f, ")");
break;
}
}
/* printtype - print details of type ty on fd */
void printtype(Type ty, int fd) {
static unsigned mark;
prtype(ty, fd == 1 ? stdout : stderr, 0, ++mark);
fprint(fd == 1 ? stdout : stderr, "\n");
}
/* typestring - return ty as C declaration for str, which may be "" */
char *typestring(Type ty, char *str) {
for ( ; ty; ty = ty->type) {
Symbol p;
switch (ty->op) {
case CONST+VOLATILE: case CONST: case VOLATILE:
if (isptr(ty->type))
str = stringf("%k %s", ty->op, str);
else
return stringf("%k %s", ty->op, typestring(ty->type, str));
break;
case STRUCT: case UNION: case ENUM:
assert(ty->u.sym);
if ((p = findtype(ty)) != NULL)
return *str ? stringf("%s %s", p->name, str) : p->name;
if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9')
warning("unnamed %k in prototype\n", ty->op);
if (*str)
return stringf("%k %s %s", ty->op, ty->u.sym->name, str);
else
return stringf("%k %s", ty->op, ty->u.sym->name);
case VOID: case FLOAT: case INT: case UNSIGNED:
return *str ? stringf("%s %s", ty->u.sym->name, str) : ty->u.sym->name;
case POINTER:
if (!ischar(ty->type) && (p = findtype(ty)) != NULL)
return *str ? stringf("%s %s", p->name, str) : p->name;
str = stringf(isarray(ty->type) || isfunc(ty->type) ? "(*%s)" : "*%s", str);
break;
case FUNCTION:
if ((p = findtype(ty)) != NULL)
return *str ? stringf("%s %s", p->name, str) : p->name;
if (ty->u.f.proto == 0)
str = stringf("%s()", str);
else if (ty->u.f.proto[0]) {
int i;
str = stringf("%s(%s", str, typestring(ty->u.f.proto[0], ""));
for (i = 1; ty->u.f.proto[i]; i++)
if (ty->u.f.proto[i] == voidtype)
str = stringf("%s, ...", str);
else
str = stringf("%s, %s", str, typestring(ty->u.f.proto[i], ""));
str = stringf("%s)", str);
} else
str = stringf("%s(void)", str);
break;
case ARRAY:
if ((p = findtype(ty)) != NULL)
return *str ? stringf("%s %s", p->name, str) : p->name;
if (ty->type && ty->type->size > 0)
str = stringf("%s[%d]", str, ty->size/ty->type->size);
else
str = stringf("%s[]", str);
break;
default: assert(0);
}
}
assert(0); return 0;
}