diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..a089bb3 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1536 @@ +Mon Dec 10 06:51:39 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: refactoring: rename rule: + memberlist -> member_list. + +Mon Dec 10 06:45:13 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: refactoring: rename rule: + ifstmt -> if_stmt, etc. + +Mon Dec 10 06:36:33 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: fix&test term/primary + change. + + * net/loveruby/cflat/parser/Parser.jj: remove useles LOOKAHEADs. + +Mon Dec 10 04:57:38 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: add explicitly. + +Mon Dec 10 03:09:53 2007 Minero Aoki + + * test/test.sh: test function pointer. + +Mon Dec 10 03:07:34 2007 Minero Aoki + + * net/loveruby/cflat/compiler/CodeGenerator.java: too few + dereference to call function from pointer. + + * net/loveruby/cflat/ast/UndefinedFunction.java: needs "$" + (immediate value) prefix to get undefined function address. + +Mon Dec 10 02:35:23 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: support function pointer. + + * net/loveruby/cflat/parser/Parser.jj: parse function type. + + * net/loveruby/cflat/parser/Parser.jj: Function's type is a + pointer to a function. + + * net/loveruby/cflat/type/TypeRef.java: new method + #isFunctionType. + + * net/loveruby/cflat/type/FunctionType.java (textize): show + parameter types. + + * net/loveruby/cflat/type/FunctionTypeRef.java: new file. + + * net/loveruby/cflat/type/TypeTable.java (get): resolve + FunctionTypeRef. + + * net/loveruby/cflat/ast/Params.java: refactoring: rename method: + variables -> parameters. + + * net/loveruby/cflat/ast/FixedParams.java: ditto. + + * net/loveruby/cflat/ast/VarParams.java: ditto. + + * net/loveruby/cflat/ast/DefinedFunction.java: ditto. + + * net/loveruby/cflat/ast/UndefinedFunction.java: ditto. + + * net/loveruby/cflat/ast/Params.java: new method #equals. + + * net/loveruby/cflat/ast/FixedParams.java: ditto. + + * net/loveruby/cflat/ast/VarParams.java: ditto. + + * net/loveruby/cflat/ast/Params.java: new method #internTypes. + + * net/loveruby/cflat/ast/FixedParams.java: ditto. + + * net/loveruby/cflat/ast/VarParams.java: ditto. + + * net/loveruby/cflat/ast/Params.java: new method #typeRefs. + + * net/loveruby/cflat/ast/FixedParams.java: ditto. + + * net/loveruby/cflat/ast/VarParams.java: ditto. + + * net/loveruby/cflat/ast/UndefinedFunction.java (address): does + not need symbol prefix "_". + + * net/loveruby/cflat/asm/Assembler.java: do not escape printable + chars. + + * test/funcptr.cb: test function pointer (not passed yet). + + * test/Makefile: build it. + +Sun Dec 9 23:47:32 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: accept arbitrary expression + for base pointer. + + * net/loveruby/cflat/ast/FuncallNode.java: ditto. + + * net/loveruby/cflat/compiler/Visitor.java: ditto. + + * net/loveruby/cflat/compiler/CodeGenerator.java: support function + pointer (not tested yet). + + * net/loveruby/cflat/compiler/CodeGenerator.java: support prefix + increment (not tested yet). + + * net/loveruby/cflat/compiler/CodeGenerator.java: support prefix + decrement (not tested yet). + + * net/loveruby/cflat/asm/Assembler.java: new method #ptrcall to + support function pointer. + +Sun Dec 9 23:04:04 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: parse composite literal + ({1,2,3,...}) as variable initializer or RHS. + + * net/loveruby/cflat/compiler/CodeGenerator.java: compile + ptr->memb as LHS. + + * net/loveruby/cflat/compiler/CodeGenerator.java: compile + ptr->memb as RHS. + + * net/loveruby/cflat/compiler/CodeGenerator.java: optimize *ptr + (reduce 1 mov). + + * net/loveruby/cflat/compiler/TypeResolver.java: refactoring: + rename method: visitComplexType -> resolveComplexType. + + * net/loveruby/cflat/ast/DereferenceNode.java: remove FIXME tag. + + * net/loveruby/cflat/ast/PtrMemberNode.java: implements LHSNode. + + * net/loveruby/cflat/ast/PtrMemberNode.java: new method + #isConstantAddress, #address, #offset. + + * net/loveruby/cflat/ast/MemberNode.java: refactoring: new method + #baseType. + + * net/loveruby/cflat/ast/CompositeLiteralNode.java: new class. + + * test/ptrmemb.cb: test ptr->memb (as LHS, RHS). + + * test/Makefile: build it. + + * test/test.sh: run it. + +Sun Dec 9 20:49:08 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: support UTF-8 input. + + * build.properties.mbp: new file. + + * test/mbc.cb: test multibyte input. + + * test/Makefile: build it. + +Tue Dec 4 11:45:59 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: change rule order. + +Tue Dec 4 10:44:42 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: refactoring: clean + assign(). + +Mon Dec 3 01:39:45 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: allow multiple defvar in + one statement. + + * test/defvar.cb: test it. + + * test/assign.cb: test cascaded assignment: x=y=1. + +Sun Dec 2 19:31:33 2007 Minero Aoki + + * test/funcall-semcheck.cb: test calling function existence check. + +Sat Dec 1 23:32:04 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: output error message. + + * test/cast.cb: test cast expr. + + * test/block.cb: test immediate block. + +Sat Dec 1 23:07:13 2007 Minero Aoki + + * net/loveruby/cflat/ast/Variable.java: is now superclass of + Defined/Undefined variable. + + * net/loveruby/cflat/ast/DefinedVariable.java: new file. + + * net/loveruby/cflat/ast/UndefinedVariable.java: new file. + + * net/loveruby/cflat/ast/DefinitionVisitor.java: support them. + + * net/loveruby/cflat/ast/Declarations.java: holds vardecls. + + * net/loveruby/cflat/parser/Parser.jj: generate Defined/Undefined + Variable. + + * net/loveruby/cflat/ast/Parameter.java: inherits DefinedVariable. + + * net/loveruby/cflat/ast/ToplevelScope.java: follow changes. + + * net/loveruby/cflat/compiler/CodeGenerator.java: ditto. + + * net/loveruby/cflat/compiler/TypeResolver.java: ditto. + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java: ditto. + + * net/loveruby/cflat/ast/Function.java: is now superclass of + Defined/Undefined functio. + + * net/loveruby/cflat/ast/DefinedFunction.java: new file. + + * net/loveruby/cflat/ast/UndefinedFunction.java: new file. + + * net/loveruby/cflat/ast/Scope.java: warn unused variable. + + * net/loveruby/cflat/ast/Entity.java: add reference counter. + +Sat Dec 1 21:06:25 2007 Minero Aoki + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java: check + duplicated parameter. + + * net/loveruby/cflat/compiler/Compiler.java: pass ErrorHandler to + resolver. + + * net/loveruby/cflat/ast/Scope.java: ditto. + + * net/loveruby/cflat/ast/ToplevelScope.java: ditto. + + * test/test.sh: check break out of loop. + + * test/test.sh: check continue out of loop. + + * test/test.sh: check duplicated parameter. + +Sat Dec 1 20:20:34 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: implement switch stmt. + + * net/loveruby/cflat/compiler/JumpResolver.java: resolve break + from switch. + + * net/loveruby/cflat/compiler/CodeGenerator.java: compile switch + stmt. + + * net/loveruby/cflat/compiler/Visitor.java: visit SwitchNode, + CaseNode. + + * net/loveruby/cflat/ast/ASTVisitor.java; dito. + + * net/loveruby/cflat/ast/SwitchNode.java: new file. + + * net/loveruby/cflat/ast/CaseNode.java: new file. + + * net/loveruby/cflat/ast/BreakableStmt.java: new file. + + * net/loveruby/cflat/ast/ContinueableStmt.java: new file. + + * net/loveruby/cflat/ast/LoopNode.java: is breakable and + continueable. + + * net/loveruby/cflat/parser/Parser.jj: implement goto stmt. + + * net/loveruby/cflat/compiler/JumpResolver.java: resolve goto + jump. + + * net/loveruby/cflat/compiler/CodeGenerator.java: compile + GotoNode. + + * net/loveruby/cflat/compiler/Visitor.java: visit GotoNode. + + * net/loveruby/cflat/ast/ASTVisitor.java; ditto. + + * net/loveruby/cflat/ast/DefinedFunction.java: manage goto labels. + + * net/loveruby/cflat/ast/GotoNode.java: new file. + + * net/loveruby/cflat/ast/LabelNode.java: new file. + + * net/loveruby/cflat/parser/Parser.jj: support recursive import. + + * net/loveruby/cflat/compiler/LibraryLoader.java: new file. + + * net/loveruby/cflat/ast/AST.java: ditto. + + * net/loveruby/cflat/ast/Declarations.java: new method #add. + + * net/loveruby/cflat/compiler/Compiler.java: support error + handling. + + * net/loveruby/cflat/compiler/ErrorHandler.java: new file. + + * net/loveruby/cflat/exception/SemanticException.java: new file. + + * net/loveruby/cflat/exception/SyntaxException.java: new file. + + * net/loveruby/cflat/exception/CompileException.java: new file. + + * net/loveruby/cflat/exception/IPCException.java: new file. + + * net/loveruby/cflat/exception/FileException.java: new file. + +Sun Nov 25 16:20:41 2007 Minero Aoki + + * test: test semantic checking on union. + +Sun Nov 25 14:17:21 2007 Minero Aoki + + * test/struct-semcheck.cb: recursive struct definition with + pointer is harmless. + +Sun Nov 25 14:13:32 2007 Minero Aoki + + * net/loveruby/cflat/compiler/TypeResolver.java: check recursive + definition of struct/union. + + * net/loveruby/cflat/type/TypeTable.java: ditto. + + * net/loveruby/cflat/type/ComplexType.java: ditto. + + * test: test it. + +Sun Nov 25 12:39:42 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: support a?b:c. + + * net/loveruby/cflat/compiler/CodeGenerator.java: ditto. + + * net/loveruby/cflat/compiler/Visitor.java: ditto. + + * net/loveruby/cflat/ast/ASTVisitor.java: ditto. + + * net/loveruby/cflat/ast/CondExprNode.java: new file. + + * test: test it. + + * test: test &&, ||. + +Sun Nov 25 11:55:56 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: support "\000" style octal + escape sequence in string/character literas. + + * net/loveruby/cflat/asm/Assembler.java: GNU as cannot parse \a. + + * test: test it. + +Sun Nov 25 09:36:17 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: support octal integer + literal. + + * net/loveruby/cflat/parser/Parser.jj: support heximal integer + literal. + + * net/loveruby/cflat/parser/Parser.jj: support U/UL/L integer + literal suffix. + + * net/loveruby/cflat/type/ArrayTypeRef.java: reject negative + length of array. + + * test: test octal/heximal integer literals. + +Sun Nov 25 07:40:49 2007 Minero Aoki + + * net/loveruby/cflat/ast/DoWhileNode.java: new node. + + * net/loveruby/cflat/ast/ASTVisitor.java: support do...while. + + * net/loveruby/cflat/compiler/Visitor.java: ditto. + + * net/loveruby/cflat/compiler/CodeGenerator.java: ditto. + + * net/loveruby/cflat/compiler/JumpResolver.java: ditto. + + * net/loveruby/cflat/parser/Parser.jj: ditto. + + * test: test it. + +Sun Oct 14 20:27:39 2007 Minero Aoki + + * test/charops.cb: new file. + + * test/ucharops.cb: new file. + + * test/shortops.cb: new file. + + * test/ushortops.cb: new file. + + * test/intops.cb: new file. + + * test/uintops.cb: new file. + + * test/longops.cb: new file. + + * test/ulongops.cb: new file. + +Sun Oct 14 18:06:15 2007 Minero Aoki + + * net/loveruby/cflat/compiler/CodeGenerator.java: support struct. + + * net/loveruby/cflat/compiler/CodeGenerator.java: support union. + + * net/loveruby/cflat/compiler/CodeGenerator.java: support array. + + * net/loveruby/cflat/compiler/CodeGenerator.java: support pointer. + + * net/loveruby/cflat/ast/ArefNode.java: implement LHSNode. + + * net/loveruby/cflat/ast/DereferenceNode.java: ditto. + + * net/loveruby/cflat/ast/LHSNode.java: ditto. + + * net/loveruby/cflat/ast/MemberNode.java: ditto. + + * net/loveruby/cflat/ast/VariableNode.java: ditto. + + * net/loveruby/cflat/type/TypeTable.java: create array type on + demand. + + * net/loveruby/cflat/type/ComplexType.java: set member offset on + demand. + + * net/loveruby/cflat/type/StructType.java: ditto. + + * net/loveruby/cflat/type/UnionType.java: ditto. + + * net/loveruby/cflat/ast/Slot.java: ditto. + + * net/loveruby/cflat/type/Type.java: #size returns long. + + * net/loveruby/cflat/type/ArrayTypeRef.java: ditto. + + * net/loveruby/cflat/type/ArrayType.java: ditto. + + * net/loveruby/cflat/type/IntegerType.java: ditto. + + * net/loveruby/cflat/type/FunctionType.java: ditto. + + * net/loveruby/cflat/type/PointerType.java: ditto. + + * net/loveruby/cflat/type/UserType.java: ditto. + + * net/loveruby/cflat/type/VoidType.java: ditto. + + * net/loveruby/cflat/asm/Assembler.java: ditto. + + * net/loveruby/cflat/asm/Label.java: new method #add. + + * net/loveruby/cflat/asm/SimpleAddress.java: ditto. + + * net/loveruby/cflat/asm/Register.java: ditto. + + * net/loveruby/cflat/asm/CompositeAddress.java: ditto. + + * net/loveruby/cflat/asm/ImmediateValue.java: dito. + + * net/loveruby/cflat/asm/AsmEntity.java: ditto. + + * net/loveruby/cflat/asm/Reference.java: ditto. + + * test/struct.cb: test struct. + + * test/union.cb: test union. + + * test/array.cb: test array. + + * test/pointer.cb: test pointer. + +Sun Oct 7 20:29:54 2007 Minero Aoki + + * net/loveruby/cflat/compiler/CodeGenerator.java (visit(IfNode)): + label was wrong. + + * net/loveruby/cflat/compiler/CodeGenerator.java (visit(ForNode)): + forgot continue label. + + * net/loveruby/cflat/compiler/JumpResolver.java: did not start + code. + + * net/loveruby/cflat/ast/ContinueNode.java (targetLabel): null + check. + + * net/loveruby/cflat/ast/BreakNode.java: ditto. + + * test/if1.cb: test if...else. + + * test/if2.cb: test if. + + * test/while1.cb: test while(0). + + * test/while2.cb: test while(1). + + * test/while3.cb: test while(i). + + * test/while-break.cb: test while + break. + + * test/while-continue.cb: test while + continue. + + * test/for1.cb: test for. + + * test/for-break.cb: test for + break. + + * test/for-continue.cb: test for + continue. + +Sun Oct 7 18:49:49 2007 Minero Aoki + + * net/loveruby/cflat/ast/LogicalNotNode.java: define #type. + + * net/loveruby/cflat/ast/ArefNode.java: ditto. + + * net/loveruby/cflat/ast/CastNode.java: ditto. + + * net/loveruby/cflat/ast/MemberNode.java: ditto. + + * net/loveruby/cflat/ast/PtrMemberNode.java: ditto. + + * net/loveruby/cflat/type/ComplexType.java: new method + #memberType. + +Sun Oct 7 18:33:58 2007 Minero Aoki + + * net/loveruby/cflat/ast/AbstractAssignNode.java: define #type. + + * test/opassign.cb: test +=, -=, *=, /=, %=, &=, |=, ^=, >>=, <<=. + + * test/inc.cb: test ++. + + * test/dec.cb: test --. + +Sun Oct 7 18:18:34 2007 Minero Aoki + + * test/eq.cb: test ==. + + * test/neq.cb: test !=. + + * test/lt.cb: test <. + + * test/lteq.cb: test <=. + + * test/gt.cb: test >. + + * test/gteq.cb: test >=. + +Sun Oct 7 18:03:25 2007 Minero Aoki + + * net/loveruby/cflat/compiler/CodeGenerator.java: <> requires + exactly cx (not ecx). + + * test/lshift.cb: test <<. + + * test/rshift.cb: test >>. + +Sun Oct 7 17:52:03 2007 Minero Aoki + + * test/logicalnot.cb: test !. + + * test/unaryplus.cb: test +@. + + * test/unaryminus.cb: test -@. + +Sun Oct 7 17:44:51 2007 Minero Aoki + + * test/bitand.cb: test &. + + * test/bitor.cb: test |. + + * test/bitxor.cb: test ^. + + * test/bitnot.cb: test ~. + +Sun Oct 7 17:28:51 2007 Minero Aoki + + * test/funcall5.cb: test more arguments. + + * test/mul.cb: test *. + + * test/div.cb: test /. + + * test/mod.cb: test %. + +Sun Oct 7 16:22:29 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: output error message + when as failed. + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java + (pushScope): handle private variables. + + * net/loveruby/cflat/compiler/CodeGenerator.java: support static + local variable (use Variable#symbol instead of #name). + + * net/loveruby/cflat/compiler/CodeGenerator.java: definedVariable + -> globalVariable. + + * net/loveruby/cflat/ast/Variable.java: new method #symbol. + + * net/loveruby/cflat/ast/Variable.java: #isDefined -> + #isInitialized. + + * net/loveruby/cflat/compiler/TypeResolver.java: ditto. + + * net/loveruby/cflat/ast/Variable.java: new method #setSequence. + + * net/loveruby/cflat/ast/AST.java (definedVariables, + commonSymbols): should get list from ToplevelScope, not + Declarations. + + * net/loveruby/cflat/ast/Scope.java: holds private variables in + privateEntities/privateEntitiesMap separately. + + * net/loveruby/cflat/ast/ToplevelScope.java: ditto. + + * test/slvar.cb: test static local variable. + + * test/slcomm.cb: test static local variable without initializer. + +Sun Oct 7 14:26:36 2007 Minero Aoki + + * net/loveruby/cflat/compiler/CodeGenerator.java: shrink stack + after return (cdecl). + + * net/loveruby/cflat/ast/FuncallNode.java: new method #type. + + * net/loveruby/cflat/ast/FuncallNode.java: new method #numArgs. + + * net/loveruby/cflat/asm/Assembler.java: new method #subq. + + * test/funcall4.cb: test stack rollback on cdecl. + + * test/add.cb: test +. + + * test/sub.cb: test -. + +Sun Oct 7 12:52:17 2007 Minero Aoki + + * net/loveruby/cflat/compiler/CodeGenerator.java: support lvar + initializer. + + * net/loveruby/cflat/compiler/CodeGenerator.java: support common + symbols. + + * net/loveruby/cflat/compiler/CodeGenerator.java: support global + variables. + + * net/loveruby/cflat/compiler/TypeResolver.java: should resolve + lvar initializer. + + * net/loveruby/cflat/ast/Entity.java: new method #size. + + * net/loveruby/cflat/ast/Entity.java: new method #alignment. + + * net/loveruby/cflat/ast/Variable.java: new method #isDefined. + + * net/loveruby/cflat/ast/Variable.java: #address holds AsmEntity, + instead of true Address (to hold Label). + + * net/loveruby/cflat/ast/AST.java: new method #definedVariables. + + * net/loveruby/cflat/ast/AST.java: new method #commonSymbols. + + * net/loveruby/cflat/ast/Frame.java: number of local variables are + long, not int. + + * net/loveruby/cflat/asm/Assembler.java: define more pseudo + operators. + + * test: test lvar initializer. + + * test: test (public/private) common symbols. + + * test: test (public/private) global variables. + +Sun Oct 7 10:27:12 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: more efficient lwsp scan. + + * net/loveruby/cflat/compiler/Compiler.java: resolve reference + before type. + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java: remove + useless import. + + * net/loveruby/cflat/compiler/TypeResolver.java: resolve local + variables first. + + * net/loveruby/cflat/compiler/CodeGenerator.java: allocate local + variables. + + * net/loveruby/cflat/ast/DefinedFunction.java: new method + #localVariables. + + * net/loveruby/cflat/ast/Scope.java: new method #variables. + + * net/loveruby/cflat/ast/Scope.java: new method #allVariables. + + * net/loveruby/cflat/ast/Scope.java: #allChildren does not include + self. + + * net/loveruby/cflat/ast/AssignNode.java: new method #type. + + * net/loveruby/cflat/ast/Node.java: #type throws error always. + + * net/loveruby/cflat/ast/VariableNode.java (entity, type, + typeNode): check if entity is null. + + * net/loveruby/cflat/ast/TypeNode.java: new method #isResolved. + + * test: test paramters and local variables. + +Sun Oct 7 04:36:56 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: fix coding style. + +Sat Sep 15 16:09:22 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: split resword/ident/number + rules. + +Fri Sep 14 13:18:03 2007 Minero Aoki + + * net/loveruby/cflat/compiler/CodeGenerator.java: refactoring: + r(Type,String) -> reg(String,Type). + +Fri Sep 14 09:30:25 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: refactoring: change + function order. + +Fri Sep 14 18:23:30 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: use JumpResolver. + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java: fork + JumpResolver.java. + + * net/loveruby/cflat/compiler/JumpResolver.java: new file. + +Fri Sep 14 09:20:02 2007 Minero Aoki + + * net/loveruby/cflat/type/StructType.java: remove useless import. + +Sun Jul 29 20:51:26 2007 Minero Aoki + + * net/loveruby/cflat/compiler/CodeGenerator.java (prologue): + allocate parameters. + + * test/test.sh: test it. + +Sun Jul 29 20:07:55 2007 Minero Aoki + + * test: add funcall tests. + +Sun Jul 29 20:05:46 2007 Minero Aoki + + * test: add basic tests. + +Sun Jul 29 19:36:47 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: convert static + methods into instance methods. + +Sun Jul 29 19:31:32 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: generate BASENAME.s + and BASENAME for source file BASENAME.cb. + +Tue Jul 17 06:52:16 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: assemble. + + * net/loveruby/cflat/compiler/CodeGenerator.java: generate + constants. + + * net/loveruby/cflat/compiler/CodeGenerator.java: generate valid + assembly. + + * net/loveruby/cflat/parser/Parser.jj: string literal wrongly + contained '"' at top. + + * net/loveruby/cflat/parser/Parser.jj: AST should hold source file + name. + + * net/loveruby/cflat/ast/AST.java: ditto. + + * net/loveruby/cflat/ast/ConstantTable.java: #strings -> #entries. + + * net/loveruby/cflat/ast/ConstantEntry.java: holds a Label. + + * net/loveruby/cflat/ast/StringLiteralNode.java (#label): returns + valid label. + + * net/loveruby/cflat/asm/Assembler.java: new method #_section. + + * net/loveruby/cflat/asm/Assembler.java: new method #_type. + + * net/loveruby/cflat/asm/Assembler.java: new method #_size. + + * net/loveruby/cflat/asm/Assembler.java: new method #_string. + + * net/loveruby/cflat/asm/Assembler.java: better output. + +Mon Jul 16 20:27:53 2007 Minero Aoki + + * test: new directory. + + * test{1,2,3,4}.cb, stdio.hb, stdlib.hb: moved under test/. + +Mon Jul 16 20:23:15 2007 Minero Aoki + + * build.xml: add source="1.4" option. + + * net/loveruby/cflat/**/*.java: change to support Java2 SE 1.4. + +Mon Jul 2 05:29:54 2007 Minero Aoki + + * net/loveruby/cflat/ast/AST.java: remove debug print. + + * net/loveruby/cflat/compiler/TypeResolver.java: ditto. + + * net/loveruby/cflat/compiler/Compiler.java: ditto. + +Mon Jul 2 05:27:42 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: import libraries. + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java + + * net/loveruby/cflat/ast/AST.java: ditto. + + * net/loveruby/cflat/parser/Parser.jj: add declfile parser. + + * net/loveruby/cflat/ast/UndefinedFunction.java: is an Entity, + instead of Declaration. + + * net/loveruby/cflat/compiler/TypeResolver.java: ditto. + + * net/loveruby/cflat/ast/DefinitionVisitor.java: ditto. + + * net/loveruby/cflat/ast/Definition.java: ditto. + + * net/loveruby/cflat/ast/Declaration.java: ditto. + + * net/loveruby/cflat/compiler/CodeGenerator.java: use AsmEntity + instead of Address. + + * net/loveruby/cflat/ast/VariableNode.java: ditto. + + * net/loveruby/cflat/ast/Entity.java: ditto. + + * net/loveruby/cflat/ast/LHSNode.java: ditto. + + * net/loveruby/cflat/ast/Node.java: ditto. + + * net/loveruby/cflat/type/TypeTable.java: put VoidType by default. + + * net/loveruby/cflat/asm/Assembler.java: add \n for each lines. + + * test1.cb: import stdio. + + * stdlib.hb: new file. + + * stdio.hb: new file. + +Mon Jul 2 04:04:57 2007 Minero Aoki + + * net/loveruby/cflat/ast/Function.java -> DefinedFunction.java. + + * net/loveruby/cflat/ast/UndefinedFunction.java: new file. + + * net/loveruby/cflat/ast/Function.java: new file (is now + interface). + + * net/loveruby/cflat/ast/*.java: ditto. + + * net/loveruby/cflat/compiler/*.java: ditto. + + * net/loveruby/cflat/parser/Parser.jj: ditto. + +Mon Jul 2 00:37:51 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: dispatch + TypeResolver. + + * net/loveruby/cflat/compiler/CodeGenerator.java: compile + condition was inversed. + + * net/loveruby/cflat/compiler/TypeResolver.java: resolve literals. + + * net/loveruby/cflat/ast/IntegerLiteralNode.java: wrong infinite + recursion. + + * net/loveruby/cflat/ast/ToplevelScope.java: raise error when + symbol cannot be resolved. + + * net/loveruby/cflat/type/PointerTypeRef.java: new method #base. + + * net/loveruby/cflat/type/TypeTable.java: resolve pointer type + ref. + +Mon Jul 2 00:09:20 2007 Minero Aoki + + * fix all compile errors. + +Sun Jul 1 22:58:00 2007 Minero Aoki + + * move net/loveruby/cflat/compiler/SimpleAddress.java, Label.java, + Register.java, Address.java, CompositeAddress.java, + LabelPool.java, ImmediateValue.java, Assembler.java, + AsmEntity.java in to net/loveruby/cflat/asm/. + +Sun Jul 1 22:52:25 2007 Minero Aoki + + * net/loveruby/cflat/**/*.java: fix many compile errors. + +Sun Jul 1 21:14:24 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Visitor.java: new common superclass + of LocalReferenceResolver, TypeResolver. + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java: ditto. + + * net/loveruby/cflat/compiler/TypeResolver.java: new file. + + * net/loveruby/cflat/compiler/Compiler.java: generate assembly + code. + + * net/loveruby/cflat/compiler/CodeGenerator.java: fix some compile + errors. + + * net/loveruby/cflat/compiler/Assembler.java: fix some compile + errors. + + * net/loveruby/cflat/compiler/Register.java: is not abstract + class. + + * net/loveruby/cflat/compiler/ImmediateAddress.java -> + ImmediateValue.java. + + * net/loveruby/cflat/compiler/Label.java: new constructor + init(String). + + * net/loveruby/cflat/parser/Parser.jj: introduce Declarations. + + * net/loveruby/cflat/ast/AST.java: ditto. + + * net/loveruby/cflat/ast/Declarations.java: new file. + + * net/loveruby/cflat/ast/DefinitionVisitor.java: new file. + + * net/loveruby/cflat/ast/Definition.java: new method + #accept(DefinitionVisitor). + + * net/loveruby/cflat/ast/Entity.java: new method + #defineIn(ToplevelScope). + + * net/loveruby/cflat/ast/TypeDefinition.java: new method + #defineIn(TypeTable). + + * net/loveruby/cflat/ast/Variable.java: ditto. + + * net/loveruby/cflat/ast/Function.java: ditto. + + * net/loveruby/cflat/ast/StructNode.java: ditto. + + * net/loveruby/cflat/ast/UnionNode.java: ditto. + + * net/loveruby/cflat/ast/TypedefNode.java: ditto. + + * net/loveruby/cflat/ast/ToplevelScope.java: ditto. + + * net/loveruby/cflat/type/TypeTable.java: ditto. + + * net/loveruby/cflat/ast/FuncallNode.java: should hold + VariableNode instead of simple Node. + +Mon Jun 18 04:53:01 2007 Minero Aoki + + * net/loveruby/cflat/compiler/CodeGenerator.java: new file. + + * net/loveruby/cflat/compiler/Assembler.java: new file. + + * net/loveruby/cflat/compiler/AsmEntity.java: new file. + + * net/loveruby/cflat/compiler/Register.java: new file. + + * net/loveruby/cflat/compiler/Address.java: new file. + + * net/loveruby/cflat/compiler/ImmediateAddress.java: new file. + + * net/loveruby/cflat/compiler/SimpleAddress.java: new file. + + * net/loveruby/cflat/compiler/CompositeAddress.java: new file. + + * net/loveruby/cflat/compiler/LabelPool.java: new file. + + * net/loveruby/cflat/compiler/Label.java: new file. + +Tue Jun 5 07:02:20 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: do not resolve AST on + parse error. + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java: should + resolve type definitions of AST, not type table. + + * net/loveruby/cflat/parser/Parser.jj: ignore empty statement. + + * net/loveruby/cflat/ast/AST.java: forgot initialize. + + * net/loveruby/cflat/ast/Definition.java: #isTypedef -> + #isUserType. + + * net/loveruby/cflat/ast/TypedefNode.java: ditto. + + * net/loveruby/cflat/ast/TypeDefinition.java: #typeRef is + required. + + * net/loveruby/cflat/ast/StructNode.java: call method of super + class. + + * net/loveruby/cflat/ast/UnionNode.java: ditto. + + * net/loveruby/cflat/ast/VariableNode.java: VariableNode may have + all entity (Variable or Function). + +Tue Jun 5 06:11:17 2007 Minero Aoki + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java: types + resolved. + + * net/loveruby/cflat/type/ComplexType.java: new common superclass + of StructType, UnionType. + + * net/loveruby/cflat/type/StructType.java: ditto. + + * net/loveruby/cflat/type/UnionType.java: ditto. + + * net/loveruby/cflat/type/UserTypeRef.java: new method #name. + + * net/loveruby/cflat/type/UserType.java: holds TypeNode instead of + Type. + + * net/loveruby/cflat/type/Type.java: new method #isUserType. + + * net/loveruby/cflat/type/TypeTable.java: new method #types. + + * net/loveruby/cflat/ast/StructNode.java: typeRef returns specific + subtype instead of generic type (TypeRef). + + * net/loveruby/cflat/ast/UnionNode.java: ditto. + + * net/loveruby/cflat/ast/ComplexTypeDefinition.java: #members + should return List to create type. + + * net/loveruby/cflat/ast/TypedefNode.java: new method #typeRef. + + * net/loveruby/cflat/ast/Slot.java: new method #typeNode. + +Tue May 29 01:40:50 2007 Minero Aoki + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java: follow + parser structure change. + + * net/loveruby/cflat/ast/ASTVisitor.java: simplify visitor + interface. + + * net/loveruby/cflat/ast/AST.java: #visit is abstract. + + * net/loveruby/cflat/ast/ComplexTypeDefinition.java: introduce new + common super class of struct/union. + + * net/loveruby/cflat/ast/Definition.java: ditto. + + * net/loveruby/cflat/ast/StructNode.java: ditto. + + * net/loveruby/cflat/ast/UnionNode.java: ditto. + + * net/loveruby/cflat/ast/TypeDefinition.java: fix typo. + + * net/loveruby/cflat/parser/Parser.jj: ComplexType requires + TypeRef. + + * net/loveruby/cflat/ast/TypeNode.java: is now mutable. + + * net/loveruby/cflat/ast/TypedefNode.java: provide #typeNode. + + * net/loveruby/cflat/ast/CastNode.java: ditto. + + * net/loveruby/cflat/ast/Entity.java: ditto. + + * net/loveruby/cflat/ast/Function.java: remove useless method. + +Mon May 21 04:29:26 2007 Minero Aoki + + * net/loveruby/cflat/parser/LocalReferenceResolver.java -> + .../compiler/LocalReferenceResolver.java. + +Mon May 21 04:10:00 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jj: fix compile errors. + + * net/loveruby/cflat/parser/LocalReferenceResolver.java: ditto. + + * net/loveruby/cflat/ast/*.java: ditto. + + * build.xml: remove jjtree related tasks. + +Mon May 21 03:40:23 2007 Minero Aoki + + * net/loveruby/cflat/ast/*.java: follow parser change (does not + depend on jjtree). + +Mon May 14 03:06:36 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jjt -> Parser.jjt + +Mon Apr 2 04:42:41 2007 Minero Aoki + + * net/loveruby/cflat/ast/StructNode.java: forgot import. + + * net/loveruby/cflat/ast/UnionNode.java: ditto. + +Mon Apr 2 04:40:47 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jjt: introduce NameNode. + + * net/loveruby/cflat/parser/Parser.jjt: TypeRef is not a Node. + + * net/loveruby/cflat/parser/LocalReferenceResolver.java + + * net/loveruby/cflat/ast/AST.java: create ToplevelScope, + TypeTable, ConstantTable here. + + * net/loveruby/cflat/ast/Definition.java: new common superclass of + all definitions (type and entity). + + * net/loveruby/cflat/ast/TypeDefinition.java: new class. + + * net/loveruby/cflat/ast/TypeRef.java -> .../TypeNode.java. + + * net/loveruby/cflat/ast/NameNode.java: new class. + + * net/loveruby/cflat/ast/CastNode.java: use NameNode. + + * net/loveruby/cflat/ast/Entity.java: ditto. + + * net/loveruby/cflat/ast/Variable.java: ditto. + + * net/loveruby/cflat/ast/StructNode.java: ditto. + + * net/loveruby/cflat/ast/UnionNode.java: ditto. + + * net/loveruby/cflat/ast/TypedefNode.java: ditto. + + * net/loveruby/cflat/ast/Slot.java: ditto. + + * net/loveruby/cflat/ast/Function.java: ditto. + + * net/loveruby/cflat/type/*Ref.java: new classes. + + * net/loveruby/cflat/type/TypeTable.java: new class. + + * net/loveruby/cflat/type/SignedLongLongType.java: new class. + + * net/loveruby/cflat/type/UnsignedLongLongType.java: new class. + + * net/loveruby/cflat/type/UserType.java: new class. + + * net/loveruby/cflat/ast/ToplevelScope.java: new method + #defineType. + +Sun Mar 25 23:54:25 2007 Minero Aoki + + * net/loveruby/cflat/ast/ListNode.java (items): utilize + SimpleNode#iterator. + + * net/loveruby/cflat/ast/AST.java (entites): entities are + child(1). + + * net/loveruby/cflat/ast/Scope.java (): initialize children. + +Sun Mar 25 23:40:08 2007 Minero Aoki + + * net/loveruby/cflat/type/Type.java: new file. + + * net/loveruby/cflat/type/VoidType.java: new file. + + * net/loveruby/cflat/type/IntegerType.java: new file. + + * net/loveruby/cflat/type/SignedCharType.java: new file. + + * net/loveruby/cflat/type/SignedShortType.java: new file. + + * net/loveruby/cflat/type/SignedIntType.java: new file. + + * net/loveruby/cflat/type/SignedLongType.java: new file. + + * net/loveruby/cflat/type/UnsignedCharType.java: new file. + + * net/loveruby/cflat/type/UnsignedShortType.java: new file. + + * net/loveruby/cflat/type/UnsignedIntType.java: new file. + + * net/loveruby/cflat/type/UnsignedLongType.java: new file. + + * net/loveruby/cflat/type/ArrayType.java: new file. + + * net/loveruby/cflat/type/PointerType.java: new file. + + * net/loveruby/cflat/type/StructType.java: new file. + + * net/loveruby/cflat/type/UnionType.java: new file. + + * net/loveruby/cflat/type/FunctionType.java: new file. + + * net/loveruby/cflat/ast/CastNode.java (typeRef): should return + TypeRef. + + * net/loveruby/cflat/ast/Params.java: new method isVararg(). + + * net/loveruby/cflat/ast/VoidParams.java: ditto. + + * net/loveruby/cflat/ast/FixedParams.java: ditto. + + * net/loveruby/cflat/ast/VarParams.java: ditto. + + * net/loveruby/cflat/ast/Entity.java: new method isType(). + + * net/loveruby/cflat/ast/Variable.java: ditto. + + * net/loveruby/cflat/ast/Function.java: ditto. + + * net/loveruby/cflat/ast/StructNode.java: is now subclass of + Entity. + + * net/loveruby/cflat/ast/UnionNode.java: ditto. + + * net/loveruby/cflat/ast/SlotNode.java -> .../Slot.java + + * net/loveruby/cflat/parser/Parser.jjt: ditto. + + * net/loveruby/cflat/ast/Scope.java (numAllEntities): initialize + lvar. + + * net/loveruby/cflat/ast/SimpleNode.java: fix syntax error. + + * net/loveruby/cflat/ast/SimpleNode.java: use deeper indent for + dump. + + * net/loveruby/cflat/ast/VariableNode.java: setVariable() -> + setEntity(). + + * net/loveruby/cflat/ast/VariableNode.java: new method type(). + + * net/loveruby/cflat/ast/MemberRef.java: disable accept(). + + * net/loveruby/cflat/parser/LocalReferenceResolver.java: fix + compile error. + +Sun Mar 25 21:40:13 2007 Minero Aoki + + * net/loveruby/cflat/ast/Toplevel.java -> .../AST.java + + * net/loveruby/cflat/ast/ToplevelScope.java: new file. + + * net/loveruby/cflat/ast/ToplevelScope.java: is not a SimpleNode. + + * net/loveruby/cflat/ast/Frame.java: ditto. + + * net/loveruby/cflat/ast/Scope.java: ditto. + + * net/loveruby/cflat/ast/BlockNode.java: forked from Scope.java. + + * net/loveruby/cflat/ast/VariableNode.java: new method #name, + #setName. + + * net/loveruby/cflat/ast/FuncallNode.java: export VariableNode. + + * net/loveruby/cflat/ast/ASTVisitor.java: follow AST structure + change. + + * net/loveruby/cflat/compiler/Compiler.java: ditto. + + * net/loveruby/cflat/parser/Parser.jjt: ditto. + + * net/loveruby/cflat/parser/LocalReferenceResolver.java: ditto. + +Sun Mar 25 20:55:41 2007 Minero Aoki + + * net/loveruby/cflat/ast/BinaryOpNode.java: new common superclass. + + * net/loveruby/cflat/ast/UnaryOpNode.java: new common superclass. + + * net/loveruby/cflat/ast/*Node.java: restruct class tree. + + * net/loveruby/cflat/ast/*Node.java: add accessor methods. + + * net/loveruby/cflat/ast/ScopeNode.java -> .../Scope.java + + * net/loveruby/cflat/ast/ToplevelNode.java -> .../Toplevel.java + +Thu Mar 22 19:30:57 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: resolve local + references. + + * net/loveruby/cflat/parser/LocalReferenceResolver.java: add all + visitor methods. + + * net/loveruby/cflat/ast/VarParamsNode.java -> .../VarParams.java + + * net/loveruby/cflat/ast/FixedParamsNode.java -> + .../FixedParams.java + + * net/loveruby/cflat/ast/VoidParamNode.java -> .../VoidParams.java + + * net/loveruby/cflat/ast/Params.java: common superclass of + VarParams, FixedParams, VoidParams. + + * net/loveruby/cflat/ast/DefvarNode.java -> .../Variable.java + + * net/loveruby/cflat/ast/DefunNode.java -> .../Function.java + + * net/loveruby/cflat/ast/Parameter.java: new class. + + * net/loveruby/cflat/ast/Entity.java: common superclass of + Variable, Parameter, Function. + + * net/loveruby/cflat/ast/ListNode.java: new method #items. + + * net/loveruby/cflat/ast/OrNode.java -> .../LogicalOrNode.java + + * net/loveruby/cflat/ast/MemberRefNode.java -> .../MemberRef.java + + * net/loveruby/cflat/ast/TypeNode.java -> .../TypeRef.java + + * net/loveruby/cflat/ast/BlockNode.java: removed (use ListNode). + + * net/loveruby/cflat/ast/ASTVisitor.java: adjust class names. + + * net/loveruby/cflat/parser/Parser.jjt: ditto. + +Thu Mar 22 16:48:27 2007 Minero Aoki + + * Binder.java -> + net/loveruby/cflat/parser/LocalReferenceResolver.java. + + * net/loveruby/cflat/ast/ParserVisitor.java -> + .../ASTVisitor.java. + + * net/loveruby/cflat/ast/*Node.java: ditto. + + * net/loveruby/cflat/parser/Node.java: ditto. + +Thu Mar 22 16:14:00 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jjt (translateEscapeChar): + throws exception on illegal escape sequence. + +Thu Mar 22 16:00:24 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jjt (parse): translate + TokenMgrError into ParseException. + + * net/loveruby/cflat/compiler/Compiler.java: use brief output. + +Thu Mar 22 15:42:47 2007 Minero Aoki + + * net/loveruby/cflat/compiler/Compiler.java: new file. + + * net/loveruby/cflat/compiler/Compiler.java: merge DumpAST and + TestParser. + + * TestParser.java: removed. + + * DumpAST.java: removed. + + * build.xml: does not build them. + +Thu Mar 22 03:30:16 2007 Minero Aoki + + * net/loveruby/cflat/ast/AbstractAssignNode.java: new file. + + * net/loveruby/cflat/ast/*AssignNode.java: introduce common + superclass, AbstractAssignNode. + +Thu Mar 22 03:13:15 2007 Minero Aoki + + * net/loveruby/cflat/parser/Node.java: new file. + +Thu Mar 22 03:08:37 2007 Minero Aoki + + * net/loveruby/cflat/ast/*Node.java: SimpleNode is in package ast. + + * build.xml: do not remove node files. + +Thu Mar 22 03:03:45 2007 Minero Aoki + + * net/loveruby/cflat/parser/Parser.jjt: set node values via + acccess methods. + + * net/loveruby/cflat/parser/Parser.jjt: stop building node files + and visitors. + + * net/loveruby/cflat/ast/*Node.java: new file. + + * net/loveruby/cflat/parser/NodeBase.java: removed. + +Thu Mar 22 01:11:23 2007 Minero Aoki + + * build.xml: default task is "compile". + + * build.xml: new task "clean". + + * build.properties: add ${build.dir}. + +Thu Mar 22 00:24:17 2007 Minero Aoki + + * move Parser.jjt and NodeBase.java to the package directory. + + * build.xml: new file. + + * build.properties: new file. + + * Makefile: removed. + + * TestParser.java: import package. + + * DumpAST.java: ditto. + +Wed Mar 21 23:38:03 2007 Minero Aoki + + * Parser.jjt: parse typedef correctly. + + * Binder.java: new file. + + * test2.cb: test typedef. + +Wed Mar 21 21:58:56 2007 Minero Aoki + + * Parser.jjt: add non-node data to AST. + + * NodeBase.java: new file. + +Wed Mar 21 18:16:16 2007 Minero Aoki + + * Parser.jjt: fork TestParser.java and DumpAST.java. + + * TestParser.java: new file. + + * DumpAST.java: new file. + + * Makefile: build them. + +Wed Mar 21 18:01:08 2007 Minero Aoki + + * jjtree again. + + * Parser.jj -> Parser.jjt + + * Makefile: build parser from jjt. + +Wed Mar 21 17:59:30 2007 Minero Aoki + + * Parser.jj: use list. + +Wed Mar 21 01:26:45 2007 Minero Aoki + + * revert to revision 22 (cancel .jj -> .jjt change). + +Wed Mar 21 01:13:49 2007 Minero Aoki + + * Parser.jj -> Parser.jjt + + * TestParser.java: new file. + +Wed Mar 21 00:20:23 2007 Minero Aoki + + * Parser.jj: helper methods should be private. + + * Parser.jj: support typedef'ed type. + + * Parser.jj: stmts rule is useless. + +Tue Mar 20 23:47:12 2007 Minero Aoki + + * Parser.jj: define parser methods as instance methods. + + * Parser.jj: add embedded action. + + * Parser.jj (CHARACTER): missing "'". + + * Parser.jj (STRING): missing '"'. + +Tue Mar 20 22:38:25 2007 Minero Aoki + + * Parser.jj: support 5U style integer literal. + + * Parser.jj: unsigned long long requires 3 lookahead. + + * Parser.jj: support ptr->memb. + + * test2.cb: test decls. + + * test3.cb: add comment. + + * test4.cb: test exprs. + +Tue Mar 20 22:10:26 2007 Minero Aoki + + * Parser.jj (params): simplify rule. + + * Makefile (test): run all tests. + + * test1.cb: new test. + + * test2.cb: new test. + + * test3.cb: new test. + + * test4.cb: new test. + +Tue Mar 20 22:09:22 2007 Minero Aoki + + * start project. + + diff --git a/README b/README new file mode 100644 index 0000000..de37094 --- /dev/null +++ b/README @@ -0,0 +1,72 @@ +CbC - Cflat Compiler +==================== + + This is the CbC, Cflat programming language compiler. + + + Requirements + ------------ + + To compile cbc itself: + + * Java SDK 1.4 or later + * JavaCC 4.0 or later + + To run cbc and compiled program: + + * Linux 2.4 or later + * GNU libc 2.3 or later + * GNU binutils (as, ld) + * util-linux (ld-linux.so.2) + + + Installation + ------------ + + # sudo ./install.sh + + or + + $ prefix=$HOME/local ./install.sh + + + License + ------- + + Modified BSD license. + For details of modified BSD license, see following: + + Copyright (c) 2007,2007 Minero Aoki. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the Minero Aoki nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY MINERO AOKI ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Contact + ------- + + CbC produced by Minero Aoki . diff --git a/ToDo b/ToDo new file mode 100644 index 0000000..5d62da0 --- /dev/null +++ b/ToDo @@ -0,0 +1,191 @@ +- generate resolved AST + - constant table + - types + - scope, frame +- integer literal + - 1, 2, 3, ... + - octal (010) + - hex (0x1f) + - 1U, 1L, 1UL +- character literal + - 'c' + - standard escape sequence ('\n', ...) + - octal escape sequence ('\077') +- string literal + - "string" + - standard escape sequence ('\n', ...) + - octal escape sequence ("\077") +- import + - single import + - recursive import + - import function + - import type +- build x86 test environment +- compile "Hello, World" +- write unit tests +- funcall + - 0 arg + - 1 arg + - 2 args + - 3 + - 4 - 10 args +- variables + - param + - reference + - assign + - lvar + - assign + - reference + - initializer + - common symbol + - assign + - reference + - global variable + - define + - reference + - assign + - private common symbol + - assign + - reference + - private global variable + - define + - assign + - reference + - function-static variable + - assign + - reference + - initializer +- op + - + + - - + - * + - / + - % +- bitwise op + - ~ + - & + - | + - ^ + - >> + - << +- unary op + - +@ + - -@ + - ! +- comparison op + - == + - != + - > + - >= + - < + - <= +- self assignment + - +=, -=, *=, ... + - ++ + - -- +- control structure + - if + - while + - flow + - break + - continue + - for + - flow + - break + - continue + - do...while + - flow + - break + - continue + - switch + - goto +- valued control structure + - && + - || + - a ? b : c +- array + - as LHS + - as RHS + - reject negative length array definition +- struct + - as LHS + - as RHS + - recursive definition with pointer +- union + - as LHS + - as RHS + - recursive definition with pointer +* composite literal {1,2,3...} + - parse (initializer) + - parse (rhs) + * type check + * code generation +- pointer + - *ptr + - *ptr = val + - ptr->memb + - ptr->memb = val +- &expr + - as RHS + * ?? as LHS +- function pointer + - refer + - call ptr(arg) +* complex LHS + - local variable + * parameter + * global variables / common symbols + * static variables + * *arr[0] = ... + * *st.memb = ... + * *ptr++ = ... + * *(ptr + N) = ... + * *(int*)ptr = ... + * their combination +- bare block ({...}) +- cast +- semantic check (control) + - reject break from out of loop/switch + - reject continue from out of loop +- semantic check (reference) + - check all symbols are resolved + - check duplicated parameters + - check if the calling function exists + - warn unused static variables + - warn unused local variables + - warn unused static functions +* semantic check (type) + - prohibit circular struct/union definition + * type check + * implicit cast + * check duplicated struct/union members + * check if struct member is valid + * check if union member is valid +- op for various types + - signed char + - signed short + - signed int + - signed long + - unsigned char + - unsigned short + - unsigned int + - unsigned long +- Multibyte input +* parse command line option +* --dump-tokens +* --dump-ast +* ?? --dump-semantic +* generate IR +* --dump-ir +* control flow graph +* --dump-cflow +* semantic check (cflow) + * warn unreachable stmt + * warn no return +* data flow graph +* --dump-dflow + * warn uninitialized use of variables +* semantic check (dflow) +* register allocation +* vararg retrieve +* 64bit long_long support diff --git a/build.properties b/build.properties new file mode 100644 index 0000000..32b951d --- /dev/null +++ b/build.properties @@ -0,0 +1,10 @@ +javacc.dir=/usr/share/java + +src.dir=. +build.dir=build +build.classes.dir=build/classes + +src.jjt.file=${src.dir}/net/loveruby/cflat/parser/Parser.jjt +build.parser.dir=${src.dir}/net/loveruby/cflat/parser +build.jj.file=${build.parser.dir}/Parser.jj +src.jj.file=${src.dir}/net/loveruby/cflat/parser/Parser.jj diff --git a/build.properties.mbp b/build.properties.mbp new file mode 100644 index 0000000..a49ff93 --- /dev/null +++ b/build.properties.mbp @@ -0,0 +1,10 @@ +javacc.dir=/opt/local/share/java + +src.dir=. +build.dir=build +build.classes.dir=build/classes + +src.jjt.file=${src.dir}/net/loveruby/cflat/parser/Parser.jjt +build.parser.dir=${src.dir}/net/loveruby/cflat/parser +build.jj.file=${build.parser.dir}/Parser.jj +src.jj.file=${src.dir}/net/loveruby/cflat/parser/Parser.jj diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..04013ce --- /dev/null +++ b/build.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/net/loveruby/cflat/asm/Address.java b/net/loveruby/cflat/asm/Address.java new file mode 100644 index 0000000..9a6ce7c --- /dev/null +++ b/net/loveruby/cflat/asm/Address.java @@ -0,0 +1,4 @@ +package net.loveruby.cflat.asm; + +abstract public class Address extends AsmEntity { +} diff --git a/net/loveruby/cflat/asm/AsmEntity.java b/net/loveruby/cflat/asm/AsmEntity.java new file mode 100644 index 0000000..f2faa57 --- /dev/null +++ b/net/loveruby/cflat/asm/AsmEntity.java @@ -0,0 +1,6 @@ +package net.loveruby.cflat.asm; + +abstract public class AsmEntity { + abstract public String toString(); + abstract public AsmEntity add(long n); +} diff --git a/net/loveruby/cflat/asm/Assembler.java b/net/loveruby/cflat/asm/Assembler.java new file mode 100644 index 0000000..5182cc0 --- /dev/null +++ b/net/loveruby/cflat/asm/Assembler.java @@ -0,0 +1,358 @@ +package net.loveruby.cflat.asm; +import net.loveruby.cflat.type.*; +import java.util.*; + +public class Assembler { + List list; + + public Assembler() { + list = new ArrayList(); + } + + public String string() { + StringBuffer buf = new StringBuffer(); + Iterator i = list.iterator(); + while (i.hasNext()) { + buf.append((String)i.next()); + buf.append("\n"); + } + return buf.toString(); + } + + protected void op(String op) { + list.add("\t" + op); + } + + protected void op(String op, AsmEntity ent) { + list.add("\t" + op + "\t" + ent.toString()); + } + + protected void op(String op, AsmEntity ent1, AsmEntity ent2) { + list.add("\t" + op + "\t" + ent1.toString() + ", " + ent2.toString()); + } + + protected void op(String op, String arg) { + list.add("\t" + op + "\t" + arg); + } + + protected void op(String op, String arg1, String arg2) { + list.add("\t" + op + "\t" + arg1 + ", " + arg2); + } + + protected void op(String op, String arg1, String arg2, String arg3) { + list.add("\t" + op + "\t" + arg1 + ", " + arg2 + ", " + arg3); + } + + public void line(String str) { + list.add(str); + } + + public void _file(String name) { + line("\t.file\t" + escapeString(name)); + } + + public void _text() { + line("\t.text"); + } + + public void _data() { + line("\t.data"); + } + + public void _section(String name) { + line("\t.section\t" + name); + } + + public void _globl(String sym) { + line(".globl " + sym); + } + + public void _local(String sym) { + line(".local " + sym); + } + + public void _comm(String sym, long size, long alignment) { + line("\t.comm\t" + sym + "," + size + "," + alignment); + } + + public void _align(long n) { + line("\t.align\t" + n); + } + + public void _type(String sym, String type) { + line("\t.type\t" + sym + ", " + type); + } + + public void _size(String sym, long size) { + _size(sym, new Long(size).toString()); + } + + public void _size(String sym, String size) { + line("\t.size\t" + sym + ", " + size); + } + + public void _byte(long n) { + line(".byte\t" + n); + } + + public void _value(long n) { + line(".value\t" + n); + } + + public void _long(long n) { + line(".long\t" + n); + } + + public void _quad(long n) { + line(".quad\t" + n); + } + + public void _string(String str) { + line("\t.string\t" + escapeString(str)); + } + + static final char bell = 007; + static final char vtab = 013; + + protected String escapeString(String str) { + StringBuffer buf = new StringBuffer(); + buf.append("\""); + for (int n = 0; n < str.length(); n++) { + char c = str.charAt(n); + if (c == '"') buf.append("\\\""); + else if (isPrintable(c)) buf.append(c); + else if (c == '\0') buf.append("\\000"); + else if (c == bell) buf.append("\\007"); + else if (c == '\b') buf.append("\\b"); + else if (c == '\t') buf.append("\\t"); + else if (c == '\n') buf.append("\\n"); + else if (c == vtab) buf.append("\\v"); + else if (c == '\f') buf.append("\\f"); + else if (c == '\r') buf.append("\\r"); + else { + buf.append("\\" + Integer.toOctalString((int)c)); + } + } + buf.append("\""); + return buf.toString(); + } + + protected boolean isPrintable(char c) { + return (' ' <= c) && (c <= '~'); + } + + public void label(String label) { + line(label + ":"); + } + + public void label(Label label) { + line(label.toString() + ":"); + } + + public void jmp(Label label) { + op("jmp", label); + } + + public void jz(Label label) { + op("jz", label); + } + + public void jnz(Label label) { + op("jnz", label); + } + + public void je(Label label) { + op("je", label); + } + + public void jne(Label label) { + op("jne", label); + } + + protected void typedOp(Type t, String op, AsmEntity a) { + op(addSuffix(op, t), a); + } + + protected void typedOp(Type t, String op, AsmEntity a, AsmEntity b) { + op(addSuffix(op, t), a, b); + } + + protected String addSuffix(String op, Type t) { + switch ((int)t.size()) { + case 1: return op + "b"; + case 2: return op + "w"; + case 4: return op + "l"; + case 8: return op + "q"; + default: + throw new Error("unknown type size: " + t.size()); + } + } + + public void cmp(Type t, Register a, Register b) { + typedOp(t, "cmp", a, b); + } + + public void sete(Register reg) { + op("sete", reg); + } + + public void setne(Register reg) { + op("setne", reg); + } + + public void setg(Register reg) { + op("setg", reg); + } + + public void setl(Register reg) { + op("setl", reg); + } + + public void setge(Register reg) { + op("setge", reg); + } + + public void setle(Register reg) { + op("setle", reg); + } + + public void test(Type type, Register a, Register b) { + typedOp(type, "test", a, b); + } + + public void pushq(Register reg) { + op("pushl", reg); + } + + public void popq(Register reg) { + op("popl", reg); + } + + public void call(String sym) { + op("call", sym); + } + + public void ptrcall(Register reg) { + op("call", "*" + reg.toString()); + } + + public void ret() { + op("ret"); + } + + public void movq(AsmEntity src, AsmEntity dest) { + op("movl", src, dest); + } + + public void mov(Type type, AsmEntity src, AsmEntity dest) { + typedOp(type, "mov", src, dest); + } + + public void movsbl(AsmEntity src, AsmEntity dest) { + op("movsbl", src, dest); + } + + public void movswl(AsmEntity src, AsmEntity dest) { + op("movswl", src, dest); + } + + public void movzb(Type type, AsmEntity src, AsmEntity dest) { + typedOp(type, "movzb", src, dest); + } + + public void movzbl(AsmEntity src, AsmEntity dest) { + op("movzbl", src, dest); + } + + public void movzwl(AsmEntity src, AsmEntity dest) { + op("movzwl", src, dest); + } + + public void leaq(AsmEntity src, AsmEntity dest) { + op("leal", src, dest); + } + + public void lea(Type type, AsmEntity src, AsmEntity dest) { + typedOp(type, "lea", src, dest); + } + + public void neg(Type type, Register reg) { + typedOp(type, "neg", reg); + } + + public void inc(Type type, AsmEntity reg) { + typedOp(type, "inc", reg); + } + + public void dec(Type type, AsmEntity reg) { + typedOp(type, "dec", reg); + } + + public void addq(AsmEntity diff, Register base) { + op("addl", diff, base); + } + + public void add(Type type, AsmEntity diff, Register base) { + typedOp(type, "add", diff, base); + } + + public void subq(AsmEntity diff, Register base) { + op("subl", diff, base); + } + + public void sub(Type type, Register diff, Register base) { + typedOp(type, "sub", diff, base); + } + + public void imulq(AsmEntity m, Register base) { + op("imull", m, base); + } + + public void imul(Type type, AsmEntity m, Register base) { + typedOp(type, "imul", m, base); + } + + public void idiv(Type type, Register base) { + typedOp(type, "idiv", base); + } + + public void not(Type type, Register reg) { + typedOp(type, "not", reg); + } + + public void and(Type type, Register bits, Register base) { + typedOp(type, "and", bits, base); + } + + public void or(Type type, Register bits, Register base) { + typedOp(type, "or", bits, base); + } + + public void xor(Type type, Register bits, Register base) { + typedOp(type, "xor", bits, base); + } + + public void sar(Type type, Register bits, Register base) { + typedOp(type, "sar", bits, base); + } + + public void sal(Type type, Register bits, Register base) { + typedOp(type, "sal", bits, base); + } + + public void shr(Type type, Register bits, Register base) { + typedOp(type, "shr", bits, base); + } + + public void shl(Type type, Register bits, Register base) { + typedOp(type, "shl", bits, base); + } + + public void rol(Type type, Register bits, Register base) { + typedOp(type, "rol", bits, base); + } + + public void ror(Type type, Register bits, Register base) { + typedOp(type, "ror", bits, base); + } +} diff --git a/net/loveruby/cflat/asm/CompositeAddress.java b/net/loveruby/cflat/asm/CompositeAddress.java new file mode 100644 index 0000000..279efa2 --- /dev/null +++ b/net/loveruby/cflat/asm/CompositeAddress.java @@ -0,0 +1,27 @@ +package net.loveruby.cflat.asm; + +public class CompositeAddress extends Address { + long offset; + Register base; + + public CompositeAddress(long off, Register reg) { + offset = off; + base = reg; + } + + public long offset() { + return offset; + } + + public Register base() { + return base; + } + + public String toString() { + return "" + offset + "(" + base.toString() + ")"; + } + + public AsmEntity add(long n) { + return new CompositeAddress(offset + n, base); + } +} diff --git a/net/loveruby/cflat/asm/ImmediateValue.java b/net/loveruby/cflat/asm/ImmediateValue.java new file mode 100644 index 0000000..d8badde --- /dev/null +++ b/net/loveruby/cflat/asm/ImmediateValue.java @@ -0,0 +1,21 @@ +package net.loveruby.cflat.asm; + +public class ImmediateValue extends AsmEntity { + long value; + + public ImmediateValue(long n) { + value = n; + } + + public long value() { + return value; + } + + public String toString() { + return "$" + value; + } + + public AsmEntity add(long n) { + return new ImmediateValue(value + n); + } +} diff --git a/net/loveruby/cflat/asm/Label.java b/net/loveruby/cflat/asm/Label.java new file mode 100644 index 0000000..4f2798b --- /dev/null +++ b/net/loveruby/cflat/asm/Label.java @@ -0,0 +1,32 @@ +package net.loveruby.cflat.asm; + +public class Label extends AsmEntity { + long seq; + String name; + + public Label(String n) { + seq = -1; + name = n; + } + + public Label(long s, String n) { + seq = s; + name = n; + } + + public long seq() { + return seq; + } + + public String name() { + return name; + } + + public String toString() { + return name; + } + + public AsmEntity add(long offset) { + throw new Error("Label#add"); // FIXME + } +} diff --git a/net/loveruby/cflat/asm/LabelPool.java b/net/loveruby/cflat/asm/LabelPool.java new file mode 100644 index 0000000..3b849af --- /dev/null +++ b/net/loveruby/cflat/asm/LabelPool.java @@ -0,0 +1,14 @@ +package net.loveruby.cflat.asm; + +public class LabelPool { + long seq; + + public LabelPool() { + seq = 0; + } + + public Label newLabel() { + seq++; + return new Label(seq, ".L" + seq); + } +} diff --git a/net/loveruby/cflat/asm/Reference.java b/net/loveruby/cflat/asm/Reference.java new file mode 100644 index 0000000..1d832a1 --- /dev/null +++ b/net/loveruby/cflat/asm/Reference.java @@ -0,0 +1,22 @@ +package net.loveruby.cflat.asm; + +public class Reference extends Address { + protected Label label; + + public Reference(Label label) { + this.label = label; + } + + public AsmEntity add(long n) { + // FIXME?? + // MemberNode#address calls this method. + // Some combination does not allows this optimization, + // caller should validate operation before call. + // Or, throw specific exception and catch it. + throw new Error("Reference#add"); + } + + public String toString() { + return "$" + label.toString(); + } +} diff --git a/net/loveruby/cflat/asm/Register.java b/net/loveruby/cflat/asm/Register.java new file mode 100644 index 0000000..5061686 --- /dev/null +++ b/net/loveruby/cflat/asm/Register.java @@ -0,0 +1,37 @@ +package net.loveruby.cflat.asm; +import net.loveruby.cflat.type.*; + +public class Register extends AsmEntity { + static public Register forType(Type t, String name) { + switch ((int)t.size()) { + case 1: return new Register(name); + case 2: return new Register(name); + case 4: return new Register("e" + name); + case 8: return new Register("r" + name); + default: + throw new Error("invalid register size: " + t.size()); + } + } + + static public Register widestRegister(String name) { + return new Register("e" + name); + } + + String name; + + public Register(String n) { + name = n; + } + + public String name() { + return name; + } + + public String toString() { + return "%" + name; + } + + public AsmEntity add(long n) { + return new CompositeAddress(n, this); + } +} diff --git a/net/loveruby/cflat/asm/SimpleAddress.java b/net/loveruby/cflat/asm/SimpleAddress.java new file mode 100644 index 0000000..29908ae --- /dev/null +++ b/net/loveruby/cflat/asm/SimpleAddress.java @@ -0,0 +1,21 @@ +package net.loveruby.cflat.asm; + +public class SimpleAddress extends Address { + Register base; + + public SimpleAddress(Register reg) { + base = reg; + } + + public Register base() { + return base; + } + + public String toString() { + return "(" + base.toString() + ")"; + } + + public AsmEntity add(long n) { + return new CompositeAddress(n, base); + } +} diff --git a/net/loveruby/cflat/ast/AST.java b/net/loveruby/cflat/ast/AST.java new file mode 100644 index 0000000..9b9daac --- /dev/null +++ b/net/loveruby/cflat/ast/AST.java @@ -0,0 +1,91 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.parser.Token; +import net.loveruby.cflat.type.TypeTable; +import java.util.*; + +public class AST extends Node { + protected String fileName; + protected Declarations declarations; + protected Token firstToken; + + protected ToplevelScope scope; + protected TypeTable typeTable; + protected ConstantTable constantTable; + + public AST(String fname, Declarations decls, Token t) { + super(); + fileName = fname; + declarations = decls; + firstToken = t; + scope = new ToplevelScope(); + typeTable = TypeTable.ilp32(); // FIXME: platform dependent + constantTable = new ConstantTable(); + } + + public String fileName() { + return fileName; + } + + public Iterator types() { + List result = new ArrayList(); + result.addAll(declarations.defstructs()); + result.addAll(declarations.defunions()); + result.addAll(declarations.typedefs()); + return result.iterator(); + } + + public Iterator entities() { + List result = new ArrayList(); + result.addAll(declarations.defvars()); + result.addAll(declarations.defuns()); + return result.iterator(); + } + + public Iterator globalVariables() { + return scope.globalVariables().iterator(); + } + + public Iterator commonSymbols() { + return scope.commonSymbols().iterator(); + } + + public boolean functionDefined() { + return !declarations.defuns().isEmpty(); + } + + public Iterator functions() { + return declarations.defuns().iterator(); + } + + public void declare(UndefinedFunction f) { + declarations.funcdecls().add(f); + } + + public Iterator declarations() { + List result = new ArrayList(); + //result.addAll(declarations.defvars()); + //result.addAll(declarations.defuns()); + result.addAll(declarations.funcdecls()); + return result.iterator(); + } + + public ToplevelScope scope() { + return scope; + } + + public TypeTable typeTable() { + return typeTable; + } + + public ConstantTable constantTable() { + return constantTable; + } + + public void dump(String prefix) { + System.out.println("FIXME: dump AST"); + } + + public void accept(ASTVisitor visitor) { + throw new Error("AST#accept"); + } +} diff --git a/net/loveruby/cflat/ast/ASTVisitor.java b/net/loveruby/cflat/ast/ASTVisitor.java new file mode 100644 index 0000000..a3bc6df --- /dev/null +++ b/net/loveruby/cflat/ast/ASTVisitor.java @@ -0,0 +1,65 @@ +package net.loveruby.cflat.ast; + +public interface ASTVisitor { + public void visit(BlockNode node); + public void visit(IfNode node); + public void visit(CondExprNode node); + public void visit(SwitchNode node); + public void visit(CaseNode node); + public void visit(WhileNode node); + public void visit(DoWhileNode node); + public void visit(ForNode node); + public void visit(BreakNode node); + public void visit(ContinueNode node); + public void visit(GotoNode node); + public void visit(LabelNode node); + public void visit(ReturnNode node); + public void visit(AssignNode node); + public void visit(PlusAssignNode node); + public void visit(MinusAssignNode node); + public void visit(MulAssignNode node); + public void visit(DivAssignNode node); + public void visit(ModAssignNode node); + public void visit(AndAssignNode node); + public void visit(OrAssignNode node); + public void visit(XorAssignNode node); + public void visit(LShiftAssignNode node); + public void visit(RShiftAssignNode node); + public void visit(LogicalOrNode node); + public void visit(LogicalAndNode node); + public void visit(GtNode node); + public void visit(LtNode node); + public void visit(GtEqNode node); + public void visit(LtEqNode node); + public void visit(EqNode node); + public void visit(NotEqNode node); + public void visit(BitwiseOrNode node); + public void visit(BitwiseXorNode node); + public void visit(BitwiseAndNode node); + public void visit(RShiftNode node); + public void visit(LShiftNode node); + public void visit(PlusNode node); + public void visit(MinusNode node); + public void visit(MulNode node); + public void visit(DivNode node); + public void visit(ModNode node); + public void visit(SuffixIncNode node); + public void visit(SuffixDecNode node); + public void visit(ArefNode node); + public void visit(MemberNode node); + public void visit(PtrMemberNode node); + public void visit(IntegerLiteralNode node); + public void visit(CharacterLiteralNode node); + public void visit(StringLiteralNode node); + public void visit(FuncallNode node); + public void visit(VariableNode node); + public void visit(UnaryPlusNode node); + public void visit(UnaryMinusNode node); + public void visit(LogicalNotNode node); + public void visit(BitwiseNotNode node); + public void visit(DereferenceNode node); + public void visit(AddressNode node); + public void visit(PrefixIncNode node); + public void visit(PrefixDecNode node); + public void visit(CastNode node); +} diff --git a/net/loveruby/cflat/ast/AbstractAssignNode.java b/net/loveruby/cflat/ast/AbstractAssignNode.java new file mode 100644 index 0000000..ac13400 --- /dev/null +++ b/net/loveruby/cflat/ast/AbstractAssignNode.java @@ -0,0 +1,24 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; + +abstract public class AbstractAssignNode extends Node { + Node lhs, rhs; + + public AbstractAssignNode(Node l, Node r) { + super(); + lhs = l; + rhs = r; + } + + public Type type() { + return lhs.type(); + } + + public Node lhs() { + return lhs; + } + + public Node rhs() { + return rhs; + } +} diff --git a/net/loveruby/cflat/ast/AddressNode.java b/net/loveruby/cflat/ast/AddressNode.java new file mode 100644 index 0000000..28062c6 --- /dev/null +++ b/net/loveruby/cflat/ast/AddressNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class AddressNode extends UnaryOpNode { + public AddressNode(Node n) { + super(n); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/AndAssignNode.java b/net/loveruby/cflat/ast/AndAssignNode.java new file mode 100644 index 0000000..6cc6513 --- /dev/null +++ b/net/loveruby/cflat/ast/AndAssignNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class AndAssignNode extends AbstractAssignNode { + public AndAssignNode(Node lhs, Node rhs) { + super(lhs, rhs); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/ArefNode.java b/net/loveruby/cflat/ast/ArefNode.java new file mode 100644 index 0000000..c72e99c --- /dev/null +++ b/net/loveruby/cflat/ast/ArefNode.java @@ -0,0 +1,38 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; + +public class ArefNode extends Node implements LHSNode { + protected Node expr, index; + + public ArefNode(Node n, Node idx) { + expr = n; + index = idx; + } + + public Type type() { + return ((ArrayType)expr.type()).base(); + } + + public Node expr() { + return expr; + } + + public Node index() { + return index; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public boolean isConstantAddress() { + // FIXME + return false; + } + + public AsmEntity address() { + // FIXME + throw new Error("ArefNode#address"); + } +} diff --git a/net/loveruby/cflat/ast/AssignNode.java b/net/loveruby/cflat/ast/AssignNode.java new file mode 100644 index 0000000..0e3ee48 --- /dev/null +++ b/net/loveruby/cflat/ast/AssignNode.java @@ -0,0 +1,29 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; + +public class AssignNode extends Node { + Node lhs, rhs; + + public AssignNode(Node l, Node r) { + super(); + lhs = l; + rhs = r; + } + + public Type type() { + // invariant(lhs.type == rhs.type) + return lhs.type(); + } + + public Node lhs() { + return lhs; + } + + public Node rhs() { + return rhs; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/BinaryOpNode.java b/net/loveruby/cflat/ast/BinaryOpNode.java new file mode 100644 index 0000000..fa9213d --- /dev/null +++ b/net/loveruby/cflat/ast/BinaryOpNode.java @@ -0,0 +1,24 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.Type; + +abstract public class BinaryOpNode extends Node { + protected Node left, right; + + public BinaryOpNode(Node l, Node r) { + super(); + left = l; + right = r; + } + + public Type type() { + return left.type(); + } + + public Node left() { + return left; + } + + public Node right() { + return right; + } +} diff --git a/net/loveruby/cflat/ast/BitwiseAndNode.java b/net/loveruby/cflat/ast/BitwiseAndNode.java new file mode 100644 index 0000000..0dcab9c --- /dev/null +++ b/net/loveruby/cflat/ast/BitwiseAndNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class BitwiseAndNode extends BinaryOpNode { + public BitwiseAndNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/BitwiseNotNode.java b/net/loveruby/cflat/ast/BitwiseNotNode.java new file mode 100644 index 0000000..1e91639 --- /dev/null +++ b/net/loveruby/cflat/ast/BitwiseNotNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class BitwiseNotNode extends UnaryOpNode { + public BitwiseNotNode(Node n) { + super(n); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/BitwiseOrNode.java b/net/loveruby/cflat/ast/BitwiseOrNode.java new file mode 100644 index 0000000..a78dac0 --- /dev/null +++ b/net/loveruby/cflat/ast/BitwiseOrNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class BitwiseOrNode extends BinaryOpNode { + public BitwiseOrNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/BitwiseXorNode.java b/net/loveruby/cflat/ast/BitwiseXorNode.java new file mode 100644 index 0000000..65dee58 --- /dev/null +++ b/net/loveruby/cflat/ast/BitwiseXorNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class BitwiseXorNode extends BinaryOpNode { + public BitwiseXorNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/BlockNode.java b/net/loveruby/cflat/ast/BlockNode.java new file mode 100644 index 0000000..384087b --- /dev/null +++ b/net/loveruby/cflat/ast/BlockNode.java @@ -0,0 +1,34 @@ +package net.loveruby.cflat.ast; +import java.util.*; + +public class BlockNode extends Node { + protected List variables; + protected List stmts; + + public BlockNode(List vars, List ss) { + variables = vars; + stmts = ss; + } + + public Iterator variables() { + return variables.iterator(); + } + + public Iterator stmts() { + return stmts.iterator(); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + protected Scope scope; + + public Scope scope() { + return scope; + } + + public void setScope(Scope s) { + scope = s; + } +} diff --git a/net/loveruby/cflat/ast/BreakNode.java b/net/loveruby/cflat/ast/BreakNode.java new file mode 100644 index 0000000..821ae58 --- /dev/null +++ b/net/loveruby/cflat/ast/BreakNode.java @@ -0,0 +1,25 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public class BreakNode extends Node { + public BreakNode() { + super(); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + protected Label label; + + public void setTargetLabel(Label label) { + this.label = label; + } + + public Label targetLabel() { + if (label == null) { + throw new Error("break label is null"); + } + return label; + } +} diff --git a/net/loveruby/cflat/ast/BreakableStmt.java b/net/loveruby/cflat/ast/BreakableStmt.java new file mode 100644 index 0000000..7f9b678 --- /dev/null +++ b/net/loveruby/cflat/ast/BreakableStmt.java @@ -0,0 +1,6 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.Label; + +public interface BreakableStmt { + public Label endLabel(); +} diff --git a/net/loveruby/cflat/ast/CaseNode.java b/net/loveruby/cflat/ast/CaseNode.java new file mode 100644 index 0000000..571ce77 --- /dev/null +++ b/net/loveruby/cflat/ast/CaseNode.java @@ -0,0 +1,37 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; +import java.util.*; + +public class CaseNode extends Node { + protected LabelPool pool; + protected Label beginLabel; + protected List values; + protected BlockNode body; + + public CaseNode(LabelPool pool, List values, BlockNode body) { + super(); + this.pool = pool; + this.values = values; + this.body = body; + this.beginLabel = null; + } + + public Iterator values() { + return values.iterator(); + } + + public BlockNode body() { + return body; + } + + public Label beginLabel() { + if (beginLabel == null) { + beginLabel = pool.newLabel(); + } + return beginLabel; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/CastNode.java b/net/loveruby/cflat/ast/CastNode.java new file mode 100644 index 0000000..8f19201 --- /dev/null +++ b/net/loveruby/cflat/ast/CastNode.java @@ -0,0 +1,32 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; + +public class CastNode extends Node { + protected TypeNode typeNode; + protected Node expr; + + public CastNode(TypeNode t, Node n) { + typeNode = t; + expr = n; + } + + public void resolve(TypeTable table) { + System.err.println("FIXME: CastNode#resolve not implemented"); + } + + public Type type() { + return typeNode.type(); + } + + public TypeNode typeNode() { + return typeNode; + } + + public Node expr() { + return expr; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/CharacterLiteralNode.java b/net/loveruby/cflat/ast/CharacterLiteralNode.java new file mode 100644 index 0000000..4a967f0 --- /dev/null +++ b/net/loveruby/cflat/ast/CharacterLiteralNode.java @@ -0,0 +1,28 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; + +public class CharacterLiteralNode extends Node { + protected TypeNode typeNode; + protected long value; + + public CharacterLiteralNode(TypeRef ref, long i) { + typeNode = new TypeNode(ref); + value = i; + } + + public Type type() { + return typeNode.type(); + } + + public TypeNode typeNode() { + return typeNode; + } + + public long value() { + return value; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/ComplexTypeDefinition.java b/net/loveruby/cflat/ast/ComplexTypeDefinition.java new file mode 100644 index 0000000..27d61c6 --- /dev/null +++ b/net/loveruby/cflat/ast/ComplexTypeDefinition.java @@ -0,0 +1,30 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import java.util.*; + +abstract public class ComplexTypeDefinition extends TypeDefinition { + protected List members; + protected TypeNode typeNode; + + public ComplexTypeDefinition(TypeRef ref, String name, List membs) { + super(name); + members = membs; + typeNode = new TypeNode(ref); + } + + public boolean isComplexType() { + return true; + } + + public List members() { + return members; + } + + public TypeRef typeRef() { + return typeNode.typeRef(); + } + + public TypeNode typeNode() { + return typeNode; + } +} diff --git a/net/loveruby/cflat/ast/CompositeLiteralNode.java b/net/loveruby/cflat/ast/CompositeLiteralNode.java new file mode 100644 index 0000000..0074238 --- /dev/null +++ b/net/loveruby/cflat/ast/CompositeLiteralNode.java @@ -0,0 +1,34 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import java.util.*; + +public class CompositeLiteralNode extends Node { + protected List members; + protected Type type; + + public CompositeLiteralNode(List membs) { + this.members = membs; + } + + public Iterator members() { + return members.iterator(); + } + + public Type type() { + if (type == null) { + throw new Error("CompositeLiteralNode#type == null"); + } + return type; + } + + public void setType(Type t) { + if (type != null) { + throw new Error("CompositeLiteralNode#setType called twice"); + } + type = t; + } + + public void accept(ASTVisitor visitor) { + throw new Error("CompositeLiteralNode#accept called"); + } +} diff --git a/net/loveruby/cflat/ast/CondExprNode.java b/net/loveruby/cflat/ast/CondExprNode.java new file mode 100644 index 0000000..cb4714e --- /dev/null +++ b/net/loveruby/cflat/ast/CondExprNode.java @@ -0,0 +1,12 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public class CondExprNode extends IfNode { + public CondExprNode(LabelPool lp, Node c, Node t, Node e) { + super(lp, c, t, e); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/ConstantEntry.java b/net/loveruby/cflat/ast/ConstantEntry.java new file mode 100644 index 0000000..6cc42d2 --- /dev/null +++ b/net/loveruby/cflat/ast/ConstantEntry.java @@ -0,0 +1,28 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.AsmEntity; +import net.loveruby.cflat.asm.Label; + +public class ConstantEntry +{ + protected long id; + protected String value; + protected Label label; + + public ConstantEntry(long i, String val) { + id = i; + value = val; + label = new Label(".LC" + id); + } + + public long id() { + return id; + } + + public String value() { + return value; + } + + public Label label() { + return label; + } +} diff --git a/net/loveruby/cflat/ast/ConstantTable.java b/net/loveruby/cflat/ast/ConstantTable.java new file mode 100644 index 0000000..37da526 --- /dev/null +++ b/net/loveruby/cflat/ast/ConstantTable.java @@ -0,0 +1,30 @@ +package net.loveruby.cflat.ast; +import java.util.*; + +public class ConstantTable +{ + protected HashMap table; + protected long id; + + public ConstantTable() { + table = new HashMap(); + id = 0; + } + + public boolean isEmpty() { + return table.isEmpty(); + } + + public ConstantEntry intern(String s) { + ConstantEntry ent = (ConstantEntry)table.get(s); + if (ent == null) { + ent = new ConstantEntry(id++, s); + table.put(s, ent); + } + return ent; + } + + public Iterator entries() { + return table.values().iterator(); + } +} diff --git a/net/loveruby/cflat/ast/ContinueNode.java b/net/loveruby/cflat/ast/ContinueNode.java new file mode 100644 index 0000000..d50ad87 --- /dev/null +++ b/net/loveruby/cflat/ast/ContinueNode.java @@ -0,0 +1,25 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public class ContinueNode extends Node { + public ContinueNode() { + super(); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + protected Label label; + + public void setTargetLabel(Label label) { + this.label = label; + } + + public Label targetLabel() { + if (label == null) { + throw new Error("continue target label is null"); + } + return label; + } +} diff --git a/net/loveruby/cflat/ast/ContinueableStmt.java b/net/loveruby/cflat/ast/ContinueableStmt.java new file mode 100644 index 0000000..ec13b04 --- /dev/null +++ b/net/loveruby/cflat/ast/ContinueableStmt.java @@ -0,0 +1,6 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.Label; + +public interface ContinueableStmt { + public Label continueLabel(); +} diff --git a/net/loveruby/cflat/ast/Declaration.java b/net/loveruby/cflat/ast/Declaration.java new file mode 100644 index 0000000..0ebb1ee --- /dev/null +++ b/net/loveruby/cflat/ast/Declaration.java @@ -0,0 +1,15 @@ +package net.loveruby.cflat.ast; + +abstract public class Declaration { + protected String name; + + public Declaration(String n) { + name = n; + } + + public String name() { + return name; + } + + abstract public void accept(DefinitionVisitor visitor); +} diff --git a/net/loveruby/cflat/ast/Declarations.java b/net/loveruby/cflat/ast/Declarations.java new file mode 100644 index 0000000..150d613 --- /dev/null +++ b/net/loveruby/cflat/ast/Declarations.java @@ -0,0 +1,81 @@ +package net.loveruby.cflat.ast; +import java.util.*; + +public class Declarations { + protected List defvars, vardecls, defuns, funcdecls; + protected List defstructs, defunions, typedefs; + + public Declarations() { + defvars = new ArrayList(); + vardecls = new ArrayList(); + defuns = new ArrayList(); + funcdecls = new ArrayList(); + defstructs = new ArrayList(); + defunions = new ArrayList(); + typedefs = new ArrayList(); + } + + public void add(Declarations decls) { + vardecls.addAll(decls.vardecls()); + funcdecls.addAll(decls.funcdecls()); + defstructs.addAll(decls.defstructs()); + defunions.addAll(decls.defunions()); + typedefs.addAll(decls.typedefs()); + } + + public void addDefvar(DefinedVariable var) { + defvars.add(var); + } + + public List defvars() { + return defvars; + } + + public void addVardecl(UndefinedVariable var) { + vardecls.add(var); + } + + public List vardecls() { + return vardecls; + } + + public void addDefun(Function func) { + defuns.add(func); + } + + public List defuns() { + return defuns; + } + + public void addFuncdecl(UndefinedFunction func) { + funcdecls.add(func); + } + + public List funcdecls() { + return funcdecls; + } + + public void addDefstruct(StructNode n) { + defstructs.add(n); + } + + public List defstructs() { + return defstructs; + } + + public void addDefunion(UnionNode n) { + defunions.add(n); + } + + public List defunions() { + return defunions; + } + + public void addTypedef(TypedefNode n) { + typedefs.add(n); + } + + public List typedefs() { + return typedefs; + } +} diff --git a/net/loveruby/cflat/ast/DefinedFunction.java b/net/loveruby/cflat/ast/DefinedFunction.java new file mode 100644 index 0000000..7409785 --- /dev/null +++ b/net/loveruby/cflat/ast/DefinedFunction.java @@ -0,0 +1,115 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.compiler.ErrorHandler; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; +import net.loveruby.cflat.exception.*; +import java.util.*; + +public class DefinedFunction extends Function { + protected LabelPool labelPool; + protected Params params; + protected Node body; + protected Map jumpMap; + protected Frame frame; + + public DefinedFunction(LabelPool pool, boolean priv, TypeNode type, + String name, Params params, Node body) { + super(priv, type, name); + this.labelPool = pool; + this.params = params; + this.body = body; + this.jumpMap = new HashMap(); + } + + public Iterator parameters() { + return params.parameters(); + } + + public Node body() { + return body; + } + + public void setFrame(Frame f) { + frame = f; + } + + // returns function local variables. + // Does NOT include paramters. + // Does NOT include static local variables. + public Iterator localVariables() { + return frame.allVariables(); + } + + public boolean isDefined() { + return true; + } + + public boolean isFunction() { + return true; + } + + public void defineIn(ToplevelScope toplevel) { + toplevel.defineFunction(this); + } + + class JumpEntry { + public Label label; + public long numRefered; + public boolean isDefined; + + public JumpEntry(Label label) { + this.label = label; + numRefered = 0; + isDefined = false; + } + } + + public Label defineLabel(String name) throws SemanticException { + JumpEntry ent = getJumpEntry(name); + if (ent.isDefined) { + throw new SemanticException( + "duplicated jump labels in " + name + "(): " + name); + } + ent.isDefined = true; + return ent.label; + } + + public Label referLabel(String name) { + JumpEntry ent = getJumpEntry(name); + ent.numRefered++; + return ent.label; + } + + protected JumpEntry getJumpEntry(String name) { + JumpEntry ent = (JumpEntry)jumpMap.get(name); + if (ent == null) { + ent = new JumpEntry(labelPool.newLabel()); + jumpMap.put(name, ent); + } + return ent; + } + + public void checkJumpLinks(ErrorHandler handler) { + Iterator ents = jumpMap.entrySet().iterator(); + while (ents.hasNext()) { + Map.Entry ent = (Map.Entry)ents.next(); + String labelName = (String)ent.getKey(); + JumpEntry jump = (JumpEntry)ent.getValue(); + if (!jump.isDefined) { + handler.error("undefined label in function " + + name + ": " + labelName); + } + if (jump.numRefered == 0) { + handler.warn("useless label: " + labelName); + } + } + } + + public void accept(DefinitionVisitor visitor) { + visitor.visit(this); + } + + public AsmEntity address() { + throw new Error("must not happen: Function#address called"); + } +} diff --git a/net/loveruby/cflat/ast/DefinedVariable.java b/net/loveruby/cflat/ast/DefinedVariable.java new file mode 100644 index 0000000..f25171a --- /dev/null +++ b/net/loveruby/cflat/ast/DefinedVariable.java @@ -0,0 +1,40 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; + +public class DefinedVariable extends Variable { + protected Node initializer; + protected AsmEntity address; + + public DefinedVariable(boolean priv, TypeNode type, + String name, Node init) { + super(priv, type, name); + initializer = init; + toplevel = false; + sequence = -1; + } + + public boolean isDefined() { + return true; + } + + public boolean isInitialized() { + return (initializer != null); + } + + public Node initializer() { + return initializer; + } + + public void defineIn(ToplevelScope toplevel) { + if (isPrivate()) { + toplevel.allocatePrivateVariable(this); + } else { + toplevel.allocateVariable(this); + } + } + + public void accept(DefinitionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/Definition.java b/net/loveruby/cflat/ast/Definition.java new file mode 100644 index 0000000..2344e99 --- /dev/null +++ b/net/loveruby/cflat/ast/Definition.java @@ -0,0 +1,39 @@ +package net.loveruby.cflat.ast; + +abstract public class Definition extends Declaration { + public Definition(String name) { + super(name); + } + + public boolean isEntity() { + return false; + } + + public boolean isVariable() { + return false; + } + + public boolean isFunction() { + return false; + } + + public boolean isType() { + return false; + } + + public boolean isComplexType() { + return false; + } + + public boolean isStruct() { + return false; + } + + public boolean isUnion() { + return false; + } + + public boolean isUserType() { + return false; + } +} diff --git a/net/loveruby/cflat/ast/DefinitionVisitor.java b/net/loveruby/cflat/ast/DefinitionVisitor.java new file mode 100644 index 0000000..906dd01 --- /dev/null +++ b/net/loveruby/cflat/ast/DefinitionVisitor.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public interface DefinitionVisitor { + public void visit(DefinedVariable var); + public void visit(UndefinedVariable var); + public void visit(DefinedFunction func); + public void visit(UndefinedFunction func); + public void visit(StructNode struct); + public void visit(UnionNode union); + public void visit(TypedefNode typedef); +} diff --git a/net/loveruby/cflat/ast/DereferenceNode.java b/net/loveruby/cflat/ast/DereferenceNode.java new file mode 100644 index 0000000..4b4a0d5 --- /dev/null +++ b/net/loveruby/cflat/ast/DereferenceNode.java @@ -0,0 +1,20 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public class DereferenceNode extends UnaryOpNode implements LHSNode { + public DereferenceNode(Node n) { + super(n); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public boolean isConstantAddress() { + return false; + } + + public AsmEntity address() { + throw new Error("DereferenceNode#address"); + } +} diff --git a/net/loveruby/cflat/ast/DivAssignNode.java b/net/loveruby/cflat/ast/DivAssignNode.java new file mode 100644 index 0000000..e1d9221 --- /dev/null +++ b/net/loveruby/cflat/ast/DivAssignNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class DivAssignNode extends AbstractAssignNode { + public DivAssignNode(Node lhs, Node rhs) { + super(lhs, rhs); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/DivNode.java b/net/loveruby/cflat/ast/DivNode.java new file mode 100644 index 0000000..7cbf3be --- /dev/null +++ b/net/loveruby/cflat/ast/DivNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class DivNode extends BinaryOpNode { + public DivNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/DoWhileNode.java b/net/loveruby/cflat/ast/DoWhileNode.java new file mode 100644 index 0000000..2e7d94a --- /dev/null +++ b/net/loveruby/cflat/ast/DoWhileNode.java @@ -0,0 +1,33 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public class DoWhileNode extends LoopNode { + protected Node cond, body; + + public DoWhileNode(LabelPool pool, Node b, Node c) { + super(pool); + body = b; + cond = c; + } + + public Node body() { + return body; + } + + public Node cond() { + return cond; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + protected Label continueLabel; + + public Label continueLabel() { + if (continueLabel == null) { + continueLabel = pool.newLabel(); + } + return continueLabel; + } +} diff --git a/net/loveruby/cflat/ast/Entity.java b/net/loveruby/cflat/ast/Entity.java new file mode 100644 index 0000000..99ea0be --- /dev/null +++ b/net/loveruby/cflat/ast/Entity.java @@ -0,0 +1,53 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; + +abstract public class Entity extends Definition { + protected boolean isPrivate; + protected TypeNode typeNode; + protected long nRefered; + + public Entity(boolean priv, TypeNode t, String name) { + super(name); + isPrivate = priv; + typeNode = t; + } + + public boolean isEntity() { + return true; + } + + abstract public boolean isDefined(); + abstract public boolean isInitialized(); + + public boolean isPrivate() { + return isPrivate; + } + + public TypeNode typeNode() { + return typeNode; + } + + public Type type() { + return typeNode.type(); + } + + public long size() { + return type().size(); + } + + public long alignment() { + return 4; // FIXME: platform dependent + } + + public void refered() { + nRefered++; + } + + public boolean isRefered() { + return (nRefered > 0); + } + + abstract public void defineIn(ToplevelScope toplevel); + abstract public AsmEntity address(); +} diff --git a/net/loveruby/cflat/ast/EqNode.java b/net/loveruby/cflat/ast/EqNode.java new file mode 100644 index 0000000..bc47448 --- /dev/null +++ b/net/loveruby/cflat/ast/EqNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class EqNode extends BinaryOpNode { + public EqNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/FixedParams.java b/net/loveruby/cflat/ast/FixedParams.java new file mode 100644 index 0000000..f061bfc --- /dev/null +++ b/net/loveruby/cflat/ast/FixedParams.java @@ -0,0 +1,48 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import java.util.*; + +public class FixedParams extends Params { + protected List parameters; + + public FixedParams(List params) { + parameters = params; + } + + public Iterator parameters() { + return parameters.iterator(); + } + + protected List parametersList() { + return parameters; + } + + public boolean isVararg() { + return false; + } + + public boolean equals(Object other) { + if (!(other instanceof FixedParams)) return false; + FixedParams params = (FixedParams)other; + return parameters.equals(params.parametersList()); + } + + public Params internTypes(TypeTable table) { + Iterator it = parameters.iterator(); + List types = new ArrayList(); + while (it.hasNext()) { + types.add(table.get((TypeRef)it.next())); + } + return new FixedParams(types); + } + + public Params typeRefs() { + Iterator it = parameters.iterator(); + List typerefs = new ArrayList(); + while (it.hasNext()) { + Parameter param = (Parameter)it.next(); + typerefs.add(param.typeNode().typeRef()); + } + return new FixedParams(typerefs); + } +} diff --git a/net/loveruby/cflat/ast/ForNode.java b/net/loveruby/cflat/ast/ForNode.java new file mode 100644 index 0000000..8cea949 --- /dev/null +++ b/net/loveruby/cflat/ast/ForNode.java @@ -0,0 +1,43 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public class ForNode extends LoopNode { + protected Node init, cond, incr, body; + + public ForNode(LabelPool pool, Node ini, Node c, Node inc, Node b) { + super(pool); + init = ini; + cond = c; + incr = inc; + body = b; + } + + public Node init() { + return init; + } + + public Node cond() { + return cond; + } + + public Node incr() { + return incr; + } + + public Node body() { + return body; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + protected Label continueLabel; + + public Label continueLabel() { + if (continueLabel == null) { + continueLabel = pool.newLabel(); + } + return continueLabel; + } +} diff --git a/net/loveruby/cflat/ast/Frame.java b/net/loveruby/cflat/ast/Frame.java new file mode 100644 index 0000000..bdbeddb --- /dev/null +++ b/net/loveruby/cflat/ast/Frame.java @@ -0,0 +1,24 @@ +package net.loveruby.cflat.ast; +import java.util.*; + +public class Frame extends Scope { + public Frame(ToplevelScope up) { + super(up); + } + + public void allocatePrivateVariable(Variable var) { + throw new Error("Frame#allocatePrivateVariable called"); + } + + public long numLocalVariables() { + return bodyScope().numAllEntities(); + } + + public Iterator localVariables() { + return bodyScope().entities(); + } + + private Scope bodyScope() { + return (Scope)children.get(0); + } +} diff --git a/net/loveruby/cflat/ast/FuncallNode.java b/net/loveruby/cflat/ast/FuncallNode.java new file mode 100644 index 0000000..d62bcb1 --- /dev/null +++ b/net/loveruby/cflat/ast/FuncallNode.java @@ -0,0 +1,46 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import java.util.*; + +public class FuncallNode extends Node { + protected Node expr; + protected List args; + + public FuncallNode(Node expr, List args) { + this.expr = expr; + this.args = args; + } + + public Node expr() { + return expr; + } + + public boolean isStaticCall() { + return (expr instanceof VariableNode) && + (((VariableNode)expr).entity() instanceof Function); + } + + public Function function() { + return (Function)((VariableNode)expr).entity(); + } + + public Type type() { + return function().type(); + } + + public long numArgs() { + return args.size(); + } + + public Iterator args() { + return args.iterator(); + } + + public ListIterator finalArg() { + return args.listIterator(args.size()); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/Function.java b/net/loveruby/cflat/ast/Function.java new file mode 100644 index 0000000..777c868 --- /dev/null +++ b/net/loveruby/cflat/ast/Function.java @@ -0,0 +1,16 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; +import java.util.*; + +abstract public class Function extends Entity { + public Function(boolean priv, TypeNode t, String name) { + super(priv, t, name); + } + + public boolean isFunction() { return true; } + public boolean isInitialized() { return true; } + abstract public boolean isDefined(); + abstract public Iterator parameters(); + abstract public AsmEntity address(); +} diff --git a/net/loveruby/cflat/ast/GotoNode.java b/net/loveruby/cflat/ast/GotoNode.java new file mode 100644 index 0000000..20f53c1 --- /dev/null +++ b/net/loveruby/cflat/ast/GotoNode.java @@ -0,0 +1,29 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.Label; + +public class GotoNode extends Node { + protected String target; + protected Label label; + + public GotoNode(String target) { + super(); + this.target = target; + } + + public String target() { + return target; + } + + public void setTargetLabel(Label label) { + this.label = label; + } + + public Label targetLabel() { + if (label == null) throw new Error("goto target label is null"); + return label; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/GtEqNode.java b/net/loveruby/cflat/ast/GtEqNode.java new file mode 100644 index 0000000..466fe86 --- /dev/null +++ b/net/loveruby/cflat/ast/GtEqNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class GtEqNode extends BinaryOpNode { + public GtEqNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/GtNode.java b/net/loveruby/cflat/ast/GtNode.java new file mode 100644 index 0000000..512bf36 --- /dev/null +++ b/net/loveruby/cflat/ast/GtNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class GtNode extends BinaryOpNode { + public GtNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/IfNode.java b/net/loveruby/cflat/ast/IfNode.java new file mode 100644 index 0000000..2cc1267 --- /dev/null +++ b/net/loveruby/cflat/ast/IfNode.java @@ -0,0 +1,46 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public class IfNode extends Node { + protected Node cond, thenBody, elseBody; + protected LabelPool pool; + protected Label elseLabel, endLabel; + + public IfNode(LabelPool lp, Node c, Node t, Node e) { + super(); + pool = lp; + cond = c; + thenBody = t; + elseBody = e; + } + + public Node cond() { + return cond; + } + + public Node thenBody() { + return thenBody; + } + + public Node elseBody() { + return elseBody; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public Label elseLabel() { + if (elseLabel == null) { + elseLabel = pool.newLabel(); + } + return elseLabel; + } + + public Label endLabel() { + if (endLabel == null) { + endLabel = pool.newLabel(); + } + return endLabel; + } +} diff --git a/net/loveruby/cflat/ast/IntegerLiteralNode.java b/net/loveruby/cflat/ast/IntegerLiteralNode.java new file mode 100644 index 0000000..4ab0f8c --- /dev/null +++ b/net/loveruby/cflat/ast/IntegerLiteralNode.java @@ -0,0 +1,28 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; + +public class IntegerLiteralNode extends Node { + protected TypeNode typeNode; + protected long value; + + public IntegerLiteralNode(TypeRef ref, long i) { + typeNode = new TypeNode(ref); + value = i; + } + + public Type type() { + return typeNode.type(); + } + + public TypeNode typeNode() { + return typeNode; + } + + public long value() { + return value; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/LHSNode.java b/net/loveruby/cflat/ast/LHSNode.java new file mode 100644 index 0000000..833cde4 --- /dev/null +++ b/net/loveruby/cflat/ast/LHSNode.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public interface LHSNode { + public boolean isConstantAddress(); + public AsmEntity address(); +} diff --git a/net/loveruby/cflat/ast/LShiftAssignNode.java b/net/loveruby/cflat/ast/LShiftAssignNode.java new file mode 100644 index 0000000..11c80ba --- /dev/null +++ b/net/loveruby/cflat/ast/LShiftAssignNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class LShiftAssignNode extends AbstractAssignNode { + public LShiftAssignNode(Node lhs, Node rhs) { + super(lhs, rhs); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/LShiftNode.java b/net/loveruby/cflat/ast/LShiftNode.java new file mode 100644 index 0000000..ef71e63 --- /dev/null +++ b/net/loveruby/cflat/ast/LShiftNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class LShiftNode extends BinaryOpNode { + public LShiftNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/LabelNode.java b/net/loveruby/cflat/ast/LabelNode.java new file mode 100644 index 0000000..e975506 --- /dev/null +++ b/net/loveruby/cflat/ast/LabelNode.java @@ -0,0 +1,35 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.Label; + +public class LabelNode extends Node { + protected String name; + protected Node stmt; + protected Label label; + + public LabelNode(String name, Node stmt) { + super(); + this.name = name; + this.stmt = stmt; + } + + public String name() { + return name; + } + + public Node stmt() { + return stmt; + } + + public void setLabel(Label label) { + this.label = label; + } + + public Label label() { + if (label == null) throw new Error("label is null"); + return label; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/LogicalAndNode.java b/net/loveruby/cflat/ast/LogicalAndNode.java new file mode 100644 index 0000000..7092846 --- /dev/null +++ b/net/loveruby/cflat/ast/LogicalAndNode.java @@ -0,0 +1,23 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public class LogicalAndNode extends BinaryOpNode { + protected LabelPool pool; + protected Label endLabel; + + public LogicalAndNode(LabelPool lp, Node left, Node right) { + super(left, right); + pool = lp; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public Label endLabel() { + if (endLabel == null) { + endLabel = pool.newLabel(); + } + return endLabel; + } +} diff --git a/net/loveruby/cflat/ast/LogicalNotNode.java b/net/loveruby/cflat/ast/LogicalNotNode.java new file mode 100644 index 0000000..6457bc1 --- /dev/null +++ b/net/loveruby/cflat/ast/LogicalNotNode.java @@ -0,0 +1,23 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; + +public class LogicalNotNode extends Node { + Node expr; + + public LogicalNotNode(Node n) { + super(); + expr = n; + } + + public Type type() { + return expr.type(); + } + + public Node expr() { + return expr; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/LogicalOrNode.java b/net/loveruby/cflat/ast/LogicalOrNode.java new file mode 100644 index 0000000..ee92f34 --- /dev/null +++ b/net/loveruby/cflat/ast/LogicalOrNode.java @@ -0,0 +1,23 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public class LogicalOrNode extends BinaryOpNode { + protected LabelPool pool; + protected Label endLabel; + + public LogicalOrNode(LabelPool lp, Node left, Node right) { + super(left, right); + pool = lp; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public Label endLabel() { + if (endLabel == null) { + endLabel = pool.newLabel(); + } + return endLabel; + } +} diff --git a/net/loveruby/cflat/ast/LoopNode.java b/net/loveruby/cflat/ast/LoopNode.java new file mode 100644 index 0000000..0333964 --- /dev/null +++ b/net/loveruby/cflat/ast/LoopNode.java @@ -0,0 +1,29 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +abstract public class LoopNode extends Node + implements BreakableStmt, ContinueableStmt { + protected LabelPool pool; + protected Label begLabel, endLabel; + + public LoopNode(LabelPool lp) { + super(); + pool = lp; + } + + public Label begLabel() { + if (begLabel == null) { + begLabel = pool.newLabel(); + } + return begLabel; + } + + public Label endLabel() { + if (endLabel == null) { + endLabel = pool.newLabel(); + } + return endLabel; + } + + abstract public Label continueLabel(); +} diff --git a/net/loveruby/cflat/ast/LtEqNode.java b/net/loveruby/cflat/ast/LtEqNode.java new file mode 100644 index 0000000..990f228 --- /dev/null +++ b/net/loveruby/cflat/ast/LtEqNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class LtEqNode extends BinaryOpNode { + public LtEqNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/LtNode.java b/net/loveruby/cflat/ast/LtNode.java new file mode 100644 index 0000000..ebdc4c7 --- /dev/null +++ b/net/loveruby/cflat/ast/LtNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class LtNode extends BinaryOpNode { + public LtNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/MemberNode.java b/net/loveruby/cflat/ast/MemberNode.java new file mode 100644 index 0000000..4a264c8 --- /dev/null +++ b/net/loveruby/cflat/ast/MemberNode.java @@ -0,0 +1,45 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.AsmEntity; + +public class MemberNode extends Node implements LHSNode { + protected Node expr; + protected String name; + + public MemberNode(Node expr, String name) { + this.expr = expr; + this.name = name; + } + + public Type type() { + return baseType().memberType(name); + } + + public ComplexType baseType() { + return (ComplexType)expr.type(); + } + + public Node expr() { + return expr; + } + + public String name() { + return name; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public long offset() { + return baseType().memberOffset(name); + } + + public boolean isConstantAddress() { + return ((LHSNode)expr).isConstantAddress(); + } + + public AsmEntity address() { + return expr.address().add(offset()); + } +} diff --git a/net/loveruby/cflat/ast/MinusAssignNode.java b/net/loveruby/cflat/ast/MinusAssignNode.java new file mode 100644 index 0000000..6399695 --- /dev/null +++ b/net/loveruby/cflat/ast/MinusAssignNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class MinusAssignNode extends AbstractAssignNode { + public MinusAssignNode(Node lhs, Node rhs) { + super(lhs, rhs); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/MinusNode.java b/net/loveruby/cflat/ast/MinusNode.java new file mode 100644 index 0000000..b218256 --- /dev/null +++ b/net/loveruby/cflat/ast/MinusNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class MinusNode extends BinaryOpNode { + public MinusNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/ModAssignNode.java b/net/loveruby/cflat/ast/ModAssignNode.java new file mode 100644 index 0000000..d41b3d7 --- /dev/null +++ b/net/loveruby/cflat/ast/ModAssignNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class ModAssignNode extends AbstractAssignNode { + public ModAssignNode(Node lhs, Node rhs) { + super(lhs, rhs); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/ModNode.java b/net/loveruby/cflat/ast/ModNode.java new file mode 100644 index 0000000..7919ad1 --- /dev/null +++ b/net/loveruby/cflat/ast/ModNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class ModNode extends BinaryOpNode { + public ModNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/MulAssignNode.java b/net/loveruby/cflat/ast/MulAssignNode.java new file mode 100644 index 0000000..21feafc --- /dev/null +++ b/net/loveruby/cflat/ast/MulAssignNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class MulAssignNode extends AbstractAssignNode { + public MulAssignNode(Node lhs, Node rhs) { + super(lhs, rhs); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/MulNode.java b/net/loveruby/cflat/ast/MulNode.java new file mode 100644 index 0000000..4ff427f --- /dev/null +++ b/net/loveruby/cflat/ast/MulNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class MulNode extends BinaryOpNode { + public MulNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/Node.java b/net/loveruby/cflat/ast/Node.java new file mode 100644 index 0000000..9a10428 --- /dev/null +++ b/net/loveruby/cflat/ast/Node.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.Type; +import net.loveruby.cflat.asm.*; + +abstract public class Node { + public Node() { + } + + abstract public void accept(ASTVisitor visitor); + + public Type type() { + throw new Error("Node#type called"); + } + + public AsmEntity address() { + throw new Error("Node#address"); + } +} diff --git a/net/loveruby/cflat/ast/NotEqNode.java b/net/loveruby/cflat/ast/NotEqNode.java new file mode 100644 index 0000000..8181744 --- /dev/null +++ b/net/loveruby/cflat/ast/NotEqNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class NotEqNode extends BinaryOpNode { + public NotEqNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/OrAssignNode.java b/net/loveruby/cflat/ast/OrAssignNode.java new file mode 100644 index 0000000..e807290 --- /dev/null +++ b/net/loveruby/cflat/ast/OrAssignNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class OrAssignNode extends AbstractAssignNode { + public OrAssignNode(Node lhs, Node rhs) { + super(lhs, rhs); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/Parameter.java b/net/loveruby/cflat/ast/Parameter.java new file mode 100644 index 0000000..74a3b66 --- /dev/null +++ b/net/loveruby/cflat/ast/Parameter.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class Parameter extends DefinedVariable { + public Parameter(TypeNode type, String name) { + super(false, type, name, null); + } + + public boolean isParameter() { + return true; + } +} diff --git a/net/loveruby/cflat/ast/Params.java b/net/loveruby/cflat/ast/Params.java new file mode 100644 index 0000000..57c63e7 --- /dev/null +++ b/net/loveruby/cflat/ast/Params.java @@ -0,0 +1,15 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.TypeTable; +import java.util.*; + +abstract public class Params extends Node { + public void accept(ASTVisitor visitor) { + throw new Error("do not use Params#accept"); + } + + abstract public Iterator parameters(); + abstract public boolean isVararg(); + abstract public boolean equals(Object other); + abstract public Params internTypes(TypeTable table); + abstract public Params typeRefs(); +} diff --git a/net/loveruby/cflat/ast/PlusAssignNode.java b/net/loveruby/cflat/ast/PlusAssignNode.java new file mode 100644 index 0000000..b2c85a8 --- /dev/null +++ b/net/loveruby/cflat/ast/PlusAssignNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class PlusAssignNode extends AbstractAssignNode { + public PlusAssignNode(Node lhs, Node rhs) { + super(lhs, rhs); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/PlusNode.java b/net/loveruby/cflat/ast/PlusNode.java new file mode 100644 index 0000000..ad6881a --- /dev/null +++ b/net/loveruby/cflat/ast/PlusNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class PlusNode extends BinaryOpNode { + public PlusNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/PrefixDecNode.java b/net/loveruby/cflat/ast/PrefixDecNode.java new file mode 100644 index 0000000..22f45b8 --- /dev/null +++ b/net/loveruby/cflat/ast/PrefixDecNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class PrefixDecNode extends UnaryOpNode { + public PrefixDecNode(Node n) { + super(n); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/PrefixIncNode.java b/net/loveruby/cflat/ast/PrefixIncNode.java new file mode 100644 index 0000000..a069ed8 --- /dev/null +++ b/net/loveruby/cflat/ast/PrefixIncNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class PrefixIncNode extends UnaryOpNode { + public PrefixIncNode(Node n) { + super(n); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/PtrMemberNode.java b/net/loveruby/cflat/ast/PtrMemberNode.java new file mode 100644 index 0000000..8ada056 --- /dev/null +++ b/net/loveruby/cflat/ast/PtrMemberNode.java @@ -0,0 +1,46 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; + +public class PtrMemberNode extends Node implements LHSNode { + public Node expr; + public String name; + + public PtrMemberNode(Node n, String nm) { + expr = n; + name = nm; + } + + public Type type() { + return baseType().memberType(name); + } + + public ComplexType baseType() { + PointerType ptr = (PointerType)expr.type(); + return (ComplexType)ptr.base(); + } + + public Node expr() { + return expr; + } + + public String name() { + return name; + } + + public boolean isConstantAddress() { + return false; + } + + public AsmEntity address() { + throw new Error("PtrMemberNode#address"); + } + + public long offset() { + return baseType().memberOffset(name); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/RShiftAssignNode.java b/net/loveruby/cflat/ast/RShiftAssignNode.java new file mode 100644 index 0000000..2a27654 --- /dev/null +++ b/net/loveruby/cflat/ast/RShiftAssignNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class RShiftAssignNode extends AbstractAssignNode { + public RShiftAssignNode(Node lhs, Node rhs) { + super(lhs, rhs); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/RShiftNode.java b/net/loveruby/cflat/ast/RShiftNode.java new file mode 100644 index 0000000..9be7e6f --- /dev/null +++ b/net/loveruby/cflat/ast/RShiftNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class RShiftNode extends BinaryOpNode { + public RShiftNode(Node left, Node right) { + super(left, right); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/ReturnNode.java b/net/loveruby/cflat/ast/ReturnNode.java new file mode 100644 index 0000000..0df11ed --- /dev/null +++ b/net/loveruby/cflat/ast/ReturnNode.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.ast; + +public class ReturnNode extends Node { + Node expr; + + public ReturnNode(Node e) { + super(); + expr = e; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public Node expr() { + return expr; + } +} diff --git a/net/loveruby/cflat/ast/Scope.java b/net/loveruby/cflat/ast/Scope.java new file mode 100644 index 0000000..03a34bd --- /dev/null +++ b/net/loveruby/cflat/ast/Scope.java @@ -0,0 +1,169 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.compiler.ErrorHandler; +import net.loveruby.cflat.exception.*; +import java.util.*; + +public class Scope { + protected Scope parent; + protected List children; + + protected long numAllEntities; + protected List entities; + protected Map entitiesMap; + protected Map privateEntitiesMap; + + public Scope(Scope up) { + parent = up; + if (up != null) up.addChild(this); + children = new ArrayList(); + numAllEntities = -1; + entities = new ArrayList(); + entitiesMap = new HashMap(); + privateEntitiesMap = new HashMap(); + } + + public boolean isToplevel() { + return false; + } + + public ToplevelScope toplevel() { + Scope s = this; + while (!s.isToplevel()) { + s = s.parent; + } + return (ToplevelScope)s; + } + + // Returns parent scope. + // If this scope is a TopScope, parent() returns null. + public Scope parent() { + return parent; + } + + protected void addChild(Scope s) { + children.add(s); + } + + // Returns a list of all child scopes. + // Does NOT include myself. + protected Iterator allChildren() { + List result = new ArrayList(); + collectChildren(result); + return result.iterator(); + } + + protected void collectChildren(List buf) { + Iterator cs = children.iterator(); + while (cs.hasNext()) { + Scope c = (Scope)cs.next(); + buf.add(c); + c.collectChildren(buf); + } + } + + /** Allocates variable var in this scope. */ + public void allocateVariable(Variable var) { + checkDuplicatedVariable(var.name()); + addEntity(var); + } + + /** Allocates static variable var in this scope. + * This method causes var defined in the top scope, + * instead of this scope. + */ + public void allocateStaticLocalVariable(Variable var) { + checkDuplicatedVariable(var.name()); + toplevel().allocateStaticLocalVariable(var); + addPrivateEntity(var); + } + + protected void addEntity(Entity ent) { + entities.add(ent); + entitiesMap.put(ent.name(), ent); + } + + protected void addPrivateEntity(Entity ent) { + privateEntitiesMap.put(ent.name(), ent); + } + + protected void checkDuplicatedVariable(String name) { + if (entitiesMap.containsKey(name) + || privateEntitiesMap.containsKey(name)) { + throw new Error("duplicated variable: " + name); + } + } + + public boolean isDefinedLocally(String name) { + return (entitiesMap.containsKey(name) + || privateEntitiesMap.containsKey(name)); + } + + public Entity get(String name) throws SemanticException { + Entity ent; + ent = (Entity)(privateEntitiesMap.get(name)); + if (ent != null) return ent; + ent = (Entity)(entitiesMap.get(name)); + if (ent != null) return ent; + return parent.get(name); + } + + // Returns all function local variables defined in this scope. + // Does includes all nested local variables. + // Does NOT include static local variables. + public Iterator allVariables() { + return allEntities().iterator(); + } + + public Iterator variables() { + return entities(); + } + + public long numEntities() { + return entities.size(); + } + + // Returns local variables defined in this scope itself. + // Does NOT include nested local variables. + // Does NOT include static local variables. + public Iterator entities() { + return entities.iterator(); + } + + public long numAllEntities() { + if (numAllEntities < 0) { + Iterator cs = allChildren(); + long n = 0; + while (cs.hasNext()) { + Scope c = (Scope)cs.next(); + n += c.numEntities(); + } + numAllEntities = n; + } + return numAllEntities; + } + + protected List allEntities() { + List result = new ArrayList(); + Iterator cs = allChildren(); + while (cs.hasNext()) { + Scope c = (Scope)cs.next(); + result.addAll(c.entities); + } + return result; + } + + public void checkReferences(ErrorHandler handler) { + Iterator ents = entities.iterator(); + while (ents.hasNext()) { + Entity ent = (Entity)ents.next(); + if (ent.isDefined() && ent.isPrivate() && !ent.isRefered()) { + handler.warn("unused variable: " + ent.name()); + } + } + Iterator cs = children.iterator(); + while (cs.hasNext()) { + Scope s = (Scope)cs.next(); + s.checkReferences(handler); + } + } +} diff --git a/net/loveruby/cflat/ast/Slot.java b/net/loveruby/cflat/ast/Slot.java new file mode 100644 index 0000000..553e3b7 --- /dev/null +++ b/net/loveruby/cflat/ast/Slot.java @@ -0,0 +1,42 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; + +public class Slot { + protected TypeNode typeNode; + protected String name; + protected long offset; + + public Slot(TypeNode t, String n) { + typeNode = t; + name = n; + offset = Type.sizeUnknown; + } + + public TypeNode typeNode() { + return typeNode; + } + + public TypeRef typeRef() { + return typeNode.typeRef(); + } + + public Type type() { + return typeNode.type(); + } + + public String name() { + return name; + } + + public long size() { + return type().size(); + } + + public long offset() { + return offset; + } + + public void setOffset(long offset) { + this.offset = offset; + } +} diff --git a/net/loveruby/cflat/ast/StringLiteralNode.java b/net/loveruby/cflat/ast/StringLiteralNode.java new file mode 100644 index 0000000..8d84d7f --- /dev/null +++ b/net/loveruby/cflat/ast/StringLiteralNode.java @@ -0,0 +1,49 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; + +public class StringLiteralNode extends Node { + protected TypeNode typeNode; + protected String value; + protected ConstantEntry entry; + + public StringLiteralNode(TypeRef ref, String s) { + typeNode = new TypeNode(ref); + value = s; + } + + public TypeNode typeNode() { + return typeNode; + } + + public Type type() { + return typeNode.type(); + } + + public String value() { + return value; + } + + public void setEntry(ConstantEntry ent) { + entry = ent; + } + + public Label label() { + checkEntry(); + return entry.label(); + } + + protected long id() { + checkEntry(); + return entry.id(); + } + + protected void checkEntry() { + if (entry == null) + throw new Error("StringLiteralNode#entry not resolved"); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/StructNode.java b/net/loveruby/cflat/ast/StructNode.java new file mode 100644 index 0000000..eaff89c --- /dev/null +++ b/net/loveruby/cflat/ast/StructNode.java @@ -0,0 +1,25 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import java.util.*; + +public class StructNode extends ComplexTypeDefinition { + public StructNode(TypeRef ref, String name, List membs) { + super(ref, name, membs); + } + + public TypeRef typeRef() { + return super.typeRef(); + } + + public boolean isStruct() { + return true; + } + + public void defineIn(TypeTable table) { + table.defineStruct((StructTypeRef)typeRef(), members()); + } + + public void accept(DefinitionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/SuffixDecNode.java b/net/loveruby/cflat/ast/SuffixDecNode.java new file mode 100644 index 0000000..c292a46 --- /dev/null +++ b/net/loveruby/cflat/ast/SuffixDecNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class SuffixDecNode extends UnaryOpNode { + public SuffixDecNode(Node n) { + super(n); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/SuffixIncNode.java b/net/loveruby/cflat/ast/SuffixIncNode.java new file mode 100644 index 0000000..d735f62 --- /dev/null +++ b/net/loveruby/cflat/ast/SuffixIncNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class SuffixIncNode extends UnaryOpNode { + public SuffixIncNode(Node n) { + super(n); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/SwitchNode.java b/net/loveruby/cflat/ast/SwitchNode.java new file mode 100644 index 0000000..83d1424 --- /dev/null +++ b/net/loveruby/cflat/ast/SwitchNode.java @@ -0,0 +1,36 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; +import java.util.*; + +public class SwitchNode extends Node implements BreakableStmt { + protected LabelPool pool; + protected Node cond; + protected List cases; + protected Label endLabel; + + public SwitchNode(LabelPool pool, Node cond, List cases) { + super(); + this.pool = pool; + this.cond = cond; + this.cases = cases; + } + + public Node cond() { + return cond; + } + + public Iterator cases() { + return cases.iterator(); + } + + public Label endLabel() { + if (endLabel == null) { + endLabel = pool.newLabel(); + } + return endLabel; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/ToplevelScope.java b/net/loveruby/cflat/ast/ToplevelScope.java new file mode 100644 index 0000000..ba237b0 --- /dev/null +++ b/net/loveruby/cflat/ast/ToplevelScope.java @@ -0,0 +1,129 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.exception.*; +import java.util.*; + +public class ToplevelScope extends Scope { + protected List privateEntities; + protected Map sequenceTable; + + public ToplevelScope() { + super(null); + privateEntities = new ArrayList(); + sequenceTable = new HashMap(); + } + + public boolean isToplevel() { + return true; + } + + /*public void defineType(TypeDefinition t) { + System.err.println("FIXME: defineType"); + }*/ + + // Declare external symbols + public void declare(Entity entity) { + addEntity(entity); + } + + public void define(Entity entity) { + entity.defineIn(this); + } + + public void defineFunction(DefinedFunction f) { + if (f.isPrivate()) { + addPrivateEntity(f); + } + else { + addEntity(f); + } + } + + // Allocate public global variable or common symbol + public void allocateVariable(Variable var) { + addEntity(var); + var.toplevelDefinition(); + } + + // Allocate private global variable or common symbol + public void allocatePrivateVariable(Variable var) { + addPrivateEntity(var); + var.toplevelDefinition(); + } + + // Allocate static local variable + public void allocateStaticLocalVariable(Variable var) { + addPrivateEntity(var); + Long seq = (Long)sequenceTable.get(var.name()); + if (seq == null) { + var.setSequence(0); + sequenceTable.put(var.name(), new Long(1)); + } + else { + var.setSequence(seq.longValue()); + sequenceTable.put(var.name(), new Long(seq.longValue() + 1)); + } + } + + protected void addPrivateEntity(Entity ent) { + super.addPrivateEntity(ent); + privateEntities.add(ent); + } + + public Entity get(String name) throws SemanticException { + Entity ent; + ent = (Entity)privateEntitiesMap.get(name); + if (ent != null) return ent; + ent = (Entity)entitiesMap.get(name); + if (ent != null) return ent; + throw new SemanticException("unresolved reference: " + name); + } + + public Iterator allVariables() { + throw new Error("TopScope#allVariables called"); + /* + List result = allEntities(); + Iterator ents = privateEntitiesMap.values().iterator(); + while (ents.hasNext()) { + Entity ent = (Entity)ents.next(); + if (ent.isVariable()) { + result.add(ent); + } + } + return result.iterator(); + */ + } + + public List globalVariables() { + List result = new ArrayList(); + List src = new ArrayList(); + src.addAll(entities); + src.addAll(privateEntities); + Iterator ents = src.iterator(); + while (ents.hasNext()) { + Object ent = ents.next(); + if (ent instanceof DefinedVariable) { + DefinedVariable var = (DefinedVariable)ent; + if (var.isInitialized()) { + result.add(var); + } + } + } + return result; + } + + public List commonSymbols() { + List result = new ArrayList(); + List src = new ArrayList(); + src.addAll(entities); + src.addAll(privateEntities); + Iterator ents = src.iterator(); + while (ents.hasNext()) { + Entity ent = (Entity)ents.next(); + if (ent.isVariable() && !ent.isInitialized()) { + result.add(ent); + } + } + return result; + } +} diff --git a/net/loveruby/cflat/ast/TypeDefinition.java b/net/loveruby/cflat/ast/TypeDefinition.java new file mode 100644 index 0000000..648afce --- /dev/null +++ b/net/loveruby/cflat/ast/TypeDefinition.java @@ -0,0 +1,16 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; + +abstract public class TypeDefinition extends Definition { + public TypeDefinition(String name) { + super(name); + } + + public boolean isType() { + return true; + } + + abstract public TypeNode typeNode(); + abstract public TypeRef typeRef(); + abstract public void defineIn(TypeTable table); +} diff --git a/net/loveruby/cflat/ast/TypeNode.java b/net/loveruby/cflat/ast/TypeNode.java new file mode 100644 index 0000000..954c9aa --- /dev/null +++ b/net/loveruby/cflat/ast/TypeNode.java @@ -0,0 +1,38 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; + +public class TypeNode extends Node { + protected TypeRef typeRef; + protected Type type; + + public TypeNode(TypeRef ref) { + super(); + typeRef = ref; + } + + public void resolve(TypeTable tbl) { + // FIXME + } + + public TypeRef typeRef() { + return typeRef; + } + + public boolean isResolved() { + return (type != null); + } + + public void setType(Type t) { + if (isResolved()) throw new Error("TypeNode#setType called twice"); + type = t; + } + + public Type type() { + if (type == null) throw new Error("TypeNode not resolved"); + return type; + } + + public void accept(ASTVisitor visitor) { + throw new Error("do not call TypeNode#accept"); + } +} diff --git a/net/loveruby/cflat/ast/TypedefNode.java b/net/loveruby/cflat/ast/TypedefNode.java new file mode 100644 index 0000000..c20dc03 --- /dev/null +++ b/net/loveruby/cflat/ast/TypedefNode.java @@ -0,0 +1,35 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; + +public class TypedefNode extends TypeDefinition { + protected TypeNode typeNode; + + public TypedefNode(TypeNode t, String name) { + super(name); + typeNode = t; + } + + public boolean isUserType() { + return true; + } + + public TypeRef typeRef() { + return typeNode.typeRef(); + } + + public TypeNode typeNode() { + return typeNode; + } + + public Type type() { + return typeNode.type(); + } + + public void defineIn(TypeTable table) { + table.defineUserType(new UserTypeRef(name()), typeNode()); + } + + public void accept(DefinitionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/UnaryMinusNode.java b/net/loveruby/cflat/ast/UnaryMinusNode.java new file mode 100644 index 0000000..f2ebe34 --- /dev/null +++ b/net/loveruby/cflat/ast/UnaryMinusNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class UnaryMinusNode extends UnaryOpNode { + public UnaryMinusNode(Node n) { + super(n); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/UnaryOpNode.java b/net/loveruby/cflat/ast/UnaryOpNode.java new file mode 100644 index 0000000..b7462e2 --- /dev/null +++ b/net/loveruby/cflat/ast/UnaryOpNode.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.Type; + +abstract public class UnaryOpNode extends Node { + protected Node expr; + + public UnaryOpNode(Node n) { + expr = n; + } + + public Type type() { + return expr.type(); + } + + public Node expr() { + return expr; + } +} diff --git a/net/loveruby/cflat/ast/UnaryPlusNode.java b/net/loveruby/cflat/ast/UnaryPlusNode.java new file mode 100644 index 0000000..5ca4117 --- /dev/null +++ b/net/loveruby/cflat/ast/UnaryPlusNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class UnaryPlusNode extends UnaryOpNode { + public UnaryPlusNode(Node n) { + super(n); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/UndefinedFunction.java b/net/loveruby/cflat/ast/UndefinedFunction.java new file mode 100644 index 0000000..b747ce1 --- /dev/null +++ b/net/loveruby/cflat/ast/UndefinedFunction.java @@ -0,0 +1,38 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; +import java.util.*; + +public class UndefinedFunction extends Function { + protected Params params; + + public UndefinedFunction(TypeNode t, String name, Params ps) { + super(false, t, name); + params = ps; + } + + public Iterator parameters() { + return params.parameters(); + } + + public boolean isDefined() { + return false; + } + + public boolean isFunction() { + return true; + } + + public AsmEntity address() { + // FIXME: use immediate + return new Label("$" + name); + } + + public void accept(DefinitionVisitor visitor) { + visitor.visit(this); + } + + public void defineIn(ToplevelScope scope) { + throw new Error("UndefinedFunction#defineIn"); + } +} diff --git a/net/loveruby/cflat/ast/UndefinedVariable.java b/net/loveruby/cflat/ast/UndefinedVariable.java new file mode 100644 index 0000000..81037c1 --- /dev/null +++ b/net/loveruby/cflat/ast/UndefinedVariable.java @@ -0,0 +1,25 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; + +public class UndefinedVariable extends Variable { + public UndefinedVariable(TypeNode t, String name) { + super(true, t, name); + } + + public boolean isDefined() { return false; } + public boolean isPrivate() { return false; } + public boolean isInitialized() { return false; } + + public String symbol() { + return name(); + } + + public void accept(DefinitionVisitor visitor) { + visitor.visit(this); + } + + public void defineIn(ToplevelScope s) { + throw new Error("UndefinedVariable#defineIn called"); + } +} diff --git a/net/loveruby/cflat/ast/UnionNode.java b/net/loveruby/cflat/ast/UnionNode.java new file mode 100644 index 0000000..ab51251 --- /dev/null +++ b/net/loveruby/cflat/ast/UnionNode.java @@ -0,0 +1,25 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import java.util.*; + +public class UnionNode extends ComplexTypeDefinition { + public UnionNode(TypeRef ref, String name, List membs) { + super(ref, name, membs); + } + + public TypeRef typeRef() { + return (UnionTypeRef)super.typeRef(); + } + + public boolean isUnion() { + return true; + } + + public void defineIn(TypeTable table) { + table.defineUnion((UnionTypeRef)typeRef(), members()); + } + + public void accept(DefinitionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/ast/VarParams.java b/net/loveruby/cflat/ast/VarParams.java new file mode 100644 index 0000000..af1d687 --- /dev/null +++ b/net/loveruby/cflat/ast/VarParams.java @@ -0,0 +1,37 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import java.util.*; + +public class VarParams extends Params { + protected FixedParams params; + + public VarParams(FixedParams params) { + this.params = params; + } + + public Iterator parameters() { + return params.parameters(); + } + + public boolean isVararg() { + return true; + } + + protected FixedParams fixedParams() { + return params; + } + + public boolean equals(Object other) { + if (!(other instanceof VarParams)) return false; + VarParams params = (VarParams)other; + return params.equals(params.fixedParams()); + } + + public Params internTypes(TypeTable table) { + return new VarParams((FixedParams)params.internTypes(table)); + } + + public Params typeRefs() { + return new VarParams((FixedParams)params.typeRefs()); + } +} diff --git a/net/loveruby/cflat/ast/Variable.java b/net/loveruby/cflat/ast/Variable.java new file mode 100644 index 0000000..b00c528 --- /dev/null +++ b/net/loveruby/cflat/ast/Variable.java @@ -0,0 +1,40 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; + +abstract public class Variable extends Entity { + protected boolean toplevel; + protected long sequence; + protected AsmEntity address; + + public Variable(boolean priv, TypeNode type, String name) { + super(priv, type, name); + toplevel = false; + sequence = -1; + } + + public void toplevelDefinition() { + toplevel = true; + } + + public void setSequence(long seq) { + this.sequence = seq; + } + + public boolean isVariable() { return true; } + public boolean isParameter() { return false; } + + public String symbol() { + return (sequence < 0) ? name : (name + "." + sequence); + } + + public void setAddress(AsmEntity addr) { + address = addr; + } + + public AsmEntity address() { + if (address == null) + throw new Error("unresolved variable address"); + return address; + } +} diff --git a/net/loveruby/cflat/ast/VariableNode.java b/net/loveruby/cflat/ast/VariableNode.java new file mode 100644 index 0000000..7543b1e --- /dev/null +++ b/net/loveruby/cflat/ast/VariableNode.java @@ -0,0 +1,50 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.type.Type; +import net.loveruby.cflat.asm.*; + +public class VariableNode extends Node implements LHSNode { + protected String name; + protected Entity entity; + + public VariableNode(String n) { + super(); + name = n; + } + + public String name() { + return name; + } + + public void setEntity(Entity ent) { + entity = ent; + } + + public Entity entity() { + if (entity == null) { + throw new Error("VariableNode.entity == null"); + } + return entity; + } + + public Type type() { + return entity().type(); + } + + public TypeNode typeNode() { + return entity().typeNode(); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + // LHS node requirement + public boolean isConstantAddress() { + return true; + } + + // LHS node requirement + public AsmEntity address() { + return entity.address(); + } +} diff --git a/net/loveruby/cflat/ast/WhileNode.java b/net/loveruby/cflat/ast/WhileNode.java new file mode 100644 index 0000000..9bff2e8 --- /dev/null +++ b/net/loveruby/cflat/ast/WhileNode.java @@ -0,0 +1,28 @@ +package net.loveruby.cflat.ast; +import net.loveruby.cflat.asm.*; + +public class WhileNode extends LoopNode { + protected Node cond, body; + + public WhileNode(LabelPool pool, Node c, Node b) { + super(pool); + cond = c; + body = b; + } + + public Node cond() { + return cond; + } + + public Node body() { + return body; + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } + + public Label continueLabel() { + return begLabel(); + } +} diff --git a/net/loveruby/cflat/ast/XorAssignNode.java b/net/loveruby/cflat/ast/XorAssignNode.java new file mode 100644 index 0000000..5fcda3b --- /dev/null +++ b/net/loveruby/cflat/ast/XorAssignNode.java @@ -0,0 +1,11 @@ +package net.loveruby.cflat.ast; + +public class XorAssignNode extends AbstractAssignNode { + public XorAssignNode(Node lhs, Node rhs) { + super(lhs, rhs); + } + + public void accept(ASTVisitor visitor) { + visitor.visit(this); + } +} diff --git a/net/loveruby/cflat/compiler/CodeGenerator.java b/net/loveruby/cflat/compiler/CodeGenerator.java new file mode 100644 index 0000000..3ca428e --- /dev/null +++ b/net/loveruby/cflat/compiler/CodeGenerator.java @@ -0,0 +1,938 @@ +package net.loveruby.cflat.compiler; +import net.loveruby.cflat.ast.*; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; +import java.util.*; + +public class CodeGenerator implements ASTVisitor { + static public String generate(AST ast) { + return new CodeGenerator(new Assembler()).generateAssembly(ast); + } + + protected Assembler as; + protected DefinedFunction currentFunction; + protected TypeTable typeTable; + + public CodeGenerator(Assembler as) { + this.as = as; + } +static public void p(String s) { System.err.println(s); } + + /** Compiles "ast" and generates assembly code. */ + public String generateAssembly(AST ast) { + typeTable = ast.typeTable(); + allocateGlobalVariables(ast.globalVariables()); + allocateCommonSymbols(ast.commonSymbols()); + + as._file(ast.fileName()); + // .data + compileGlobalVariables(ast.globalVariables()); + if (!ast.constantTable().isEmpty()) { + compileConstants(ast.constantTable()); + } + // .text + if (ast.functionDefined()) { + compileFunctions(ast.functions()); + } + // .bss + compileCommonSymbols(ast.commonSymbols()); + + return as.string(); + } + + /** + * Sets address for... + * * public global variables + * * private global variables + * * static local variables + */ + protected void allocateGlobalVariables(Iterator vars) { + while (vars.hasNext()) { + Variable var = (Variable)vars.next(); + var.setAddress(globalVariableAddress(var.symbol())); + } + } + + /** + * Sets address for... + * * public common symbols + * * private common symbols + */ + protected void allocateCommonSymbols(Iterator comms) { + while (comms.hasNext()) { + Variable var = (Variable)comms.next(); + var.setAddress(commonSymbolAddress(var.symbol())); + } + } + + /** Linux/IA-32 dependent */ + // FIXME: PIC + protected AsmEntity globalVariableAddress(String sym) { + return new Label(csymbol(sym)); + } + + /** Linux/IA-32 dependent */ + // FIXME: PIC + protected AsmEntity commonSymbolAddress(String sym) { + return new Label(csymbol(sym)); + } + + /** Generates static variable entries */ + protected void compileGlobalVariables(Iterator vars) { + as._data(); + while (vars.hasNext()) { + DefinedVariable var = (DefinedVariable)vars.next(); + dataEntry(var); + } + } + + /** Generates initialized entries */ + protected void dataEntry(DefinedVariable ent) { + if (!ent.isPrivate()) { + as._globl(csymbol(ent.symbol())); + } + as._align(ent.size()); + as._type(csymbol(ent.symbol()), "@object"); + as._size(csymbol(ent.symbol()), ent.size()); + as.label(csymbol(ent.symbol())); + compileImmediate(ent.type(), ent.initializer()); + } + + /** Generates immediate values for .data section */ + protected void compileImmediate(Type type, Node n) { + // FIXME: support other constants + IntegerLiteralNode expr = (IntegerLiteralNode)n; + switch ((int)type.size()) { + case 1: as._byte(expr.value()); break; + case 2: as._value(expr.value()); break; + case 4: as._long(expr.value()); break; + case 8: as._quad(expr.value()); break; + default: + throw new Error("entry size is not 1,2,4,8"); + } + } + + /** Generates BSS entries */ + protected void compileCommonSymbols(Iterator ents) { + while (ents.hasNext()) { + Variable ent = (Variable)ents.next(); + if (ent.isPrivate()) { + as._local(csymbol(ent.symbol())); + } + as._comm(csymbol(ent.symbol()), ent.size(), ent.alignment()); + } + } + + /** Generates .rodata entry (constant strings) */ + protected void compileConstants(ConstantTable table) { + as._section(".rodata"); + Iterator ents = table.entries(); + while (ents.hasNext()) { + ConstantEntry ent = (ConstantEntry)ents.next(); + as.label(ent.label()); + as._string(ent.value()); + } + } + + /** Compiles all functions and generates .text section. */ + protected void compileFunctions(Iterator funcs) { + as._text(); + while (funcs.hasNext()) { + DefinedFunction func = (DefinedFunction)funcs.next(); + compileFunction(func); + } + } + + /** Compiles a function. */ + protected void compileFunction(DefinedFunction func) { + currentFunction = func; + String symbol = csymbol(func.name()); + as._globl(symbol); + as._type(symbol, "@function"); + as.label(symbol); + prologue(func); + allocateParameters(func); + allocateLocalVariables(func); + compile(func.body()); + epilogue(func); + as._size(symbol, ".-" + symbol); + } + + protected void compile(Node n) { + n.accept(this); + } + + // platform dependent + protected String tmpsymbol(String sym) { + return sym; + } + + // platform dependent + protected String csymbol(String sym) { + return sym; + } + + protected void prologue(DefinedFunction func) { + as.pushq(bp()); + as.movq(sp(), bp()); + } + + protected void epilogue(DefinedFunction func) { + as.label(epilogueLabel(func)); + as.movq(bp(), sp()); + as.popq(bp()); + as.ret(); + } + + protected void jmpEpilogue() { + as.jmp(new Label(epilogueLabel(currentFunction))); + } + + protected String epilogueLabel(DefinedFunction func) { + return ".L" + func.name() + "$epilogue"; + } + + /* Standard IA-32 stack frame layout (after prologue) + * + * ======================= esp (stack top) + * temporary + * variables... + * --------------------- ebp-(4*3) + * lvar 3 + * --------------------- ebp-(4*2) + * lvar 2 + * --------------------- ebp-(4*1) + * lvar 1 + * ======================= ebp + * saved ebp + * --------------------- ebp+(4*1) + * return address + * --------------------- ebp+(4*2) + * arg 1 + * --------------------- ebp+(4*3) + * arg 2 + * --------------------- ebp+(4*4) + * arg 3 + * ... + * ... + * ======================= stack bottom + */ + + /* + * Platform Dependent Stack Parameters + */ + static final protected int stackDirection = -1; // stack grows lower + static final protected long stackWordSize = 4; + // 1 for return address, 1 for saved bp. + static final protected long paramStartOffset = 2; + static final protected long usedStackWords = 0; + + protected void allocateParameters(DefinedFunction func) { + Iterator vars = func.parameters(); + long i = paramStartOffset; + while (vars.hasNext()) { + Parameter var = (Parameter)vars.next(); + var.setAddress(lvarAddressByWord(i)); + i++; + } + } + + protected CompositeAddress lvarAddressByWord(long offset) { + return new CompositeAddress(offset * stackWordSize, bp()); + } + + protected void allocateLocalVariables(DefinedFunction func) { + Iterator vars = func.localVariables(); + long len = usedStackWords * stackWordSize; + while (vars.hasNext()) { + DefinedVariable var = (DefinedVariable)vars.next(); + if (stackDirection < 0) { + len = align(len + var.size(), stackWordSize); + var.setAddress(new CompositeAddress(-len, bp())); + } + else { + var.setAddress(new CompositeAddress(len, bp())); + len = align(len + var.size(), stackWordSize); + } + } + if (len != 0) { + extendStack(len); + } + } + + protected void extendStack(long len) { + as.addq(imm(stackDirection * len), sp()); + } + + protected void shrinkStack(long len) { + as.subq(imm(stackDirection * len), sp()); + } + + protected long align(long n, long alignment) { + return (n + alignment - 1) / alignment * alignment; + } + + protected Register bp() { + return reg("bp"); + } + + protected Register sp() { + return reg("sp"); + } + + // cdecl call + // * all arguments are on stack + // * rollback stack by caller + public void visit(FuncallNode node) { + ListIterator it = node.finalArg(); + while (it.hasPrevious()) { + Node arg = (Node)it.previous(); + compile(arg); + as.pushq(reg("ax")); + } + //if (node.function().isVararg()) { + // ... + //} + if (node.isStaticCall()) { + if (node.function().isDefined()) { + as.call(csymbol(node.function().name())); + } + else { + as.call(tmpsymbol(node.function().name())); + } + } + else { // funcall via pointer + // FIXME + compile(node.expr()); + as.ptrcall(reg("ax")); + } + if (node.numArgs() > 0) { + // FIXME: >4 size arguments are not supported. + shrinkStack(node.numArgs() * stackWordSize); + } + } + + public void visit(ReturnNode node) { + if (node.expr() != null) { + compile(node.expr()); + } + jmpEpilogue(); + } + + public void visit(BlockNode node) { + Iterator vars = node.scope().variables(); + while (vars.hasNext()) { + DefinedVariable var = (DefinedVariable)vars.next(); + if (var.initializer() != null) { + compile(var.initializer()); + saveWords(var.type(), "ax", var.address()); + } + } + Iterator stmts = node.stmts(); + while (stmts.hasNext()) { + compileStmt((Node)stmts.next()); + } + } + + // needed? + protected void compileStmt(Node node) { + compile(node); + } + + public void visit(CastNode node) { + // FIXME: insert cast op here + compile(node.expr()); + } + + public void visit(IntegerLiteralNode node) { + as.mov(node.type(), imm(node.value()), reg("ax", node.type())); + } + + public void visit(CharacterLiteralNode node) { + as.mov(node.type(), imm(node.value()), reg("ax", node.type())); + } + + public void visit(StringLiteralNode node) { + loadWords(node.type(), imm(node.label()), "ax"); + } + + public void visit(VariableNode node) { + loadWords(node.type(), node.address(), "ax"); + } + + static final String PTRREG = "bx"; + + public void visit(ArefNode node) { + compileLHS(node.expr()); + as.pushq(reg(PTRREG)); + compile(node.index()); + as.movq(reg("ax"), reg("cx")); + as.popq(reg(PTRREG)); + as.imulq(imm(node.type().size()), reg("cx")); + as.addq(reg("cx"), reg(PTRREG)); + loadWords(node.type(), addr(PTRREG), "ax"); + } + + public void visit(MemberNode node) { + compileLHS(node.expr()); + loadWords(node.type(), addr2(node.offset(), PTRREG), "ax"); + } + + public void visit(PtrMemberNode node) { + compileLHS(node.expr()); + loadWords(node.type(), addr(PTRREG), PTRREG); + loadWords(node.type(), addr2(node.offset(), PTRREG), "ax"); + } + + public void visit(AssignNode node) { + // FIXME + if (((LHSNode)node.lhs()).isConstantAddress()) { + compile(node.rhs()); + saveWords(node.type(), "ax", node.lhs().address()); + } + else { + compile(node.rhs()); + as.pushq(reg("ax")); + compileLHS(node.lhs()); + // leave RHS-value on the stack + as.movq(addr("sp"), reg("ax")); + saveWords(node.type(), "ax", addr(PTRREG)); + } + } + + public void visit(DereferenceNode node) { + compileLHS(node.expr()); + as.movq(addr(PTRREG), reg("ax")); + loadWords(node.type(), addr("ax"), "ax"); + } + + public void visit(AddressNode node) { + compileLHS(node.expr()); + as.movq(reg(PTRREG), reg("ax")); + } + + protected void compileLHS(Node node) { + if (node instanceof VariableNode) { + // FIXME: support static variables + VariableNode n = (VariableNode)node; + as.leaq(n.address(), reg(PTRREG)); + } + else if (node instanceof ArefNode) { + // FIXME: support non-constant index + ArefNode n = (ArefNode)node; + //as.movq(imm(n.index().value()), reg(PTRREG)); // FIXME + as.movq(imm(((IntegerLiteralNode)n.index()).value()), reg(PTRREG)); + as.imulq(imm(n.type().size()), reg(PTRREG)); // unsigned? + as.pushq(reg(PTRREG)); + compileLHS(n.expr()); + as.popq(reg("cx")); + as.addq(reg("cx"), reg(PTRREG)); + } + else if (node instanceof MemberNode) { + MemberNode n = (MemberNode)node; + compileLHS(n.expr()); + as.addq(imm(n.offset()), reg(PTRREG)); + } + else if (node instanceof DereferenceNode) { + DereferenceNode n = (DereferenceNode)node; + compileLHS(n.expr()); + as.movq(addr(PTRREG), reg(PTRREG)); + } + else if (node instanceof PtrMemberNode) { + PtrMemberNode n = (PtrMemberNode)node; + compileLHS(n.expr()); + as.movq(addr(PTRREG), reg(PTRREG)); + as.addq(imm(n.offset()), reg(PTRREG)); + } + else if (node instanceof PrefixIncNode) { + PrefixIncNode n = (PrefixIncNode)node; + compileLHS(n.expr()); + as.addq(imm(n.expr().type().size()), reg(PTRREG)); + } + else if (node instanceof PrefixDecNode) { + PrefixDecNode n = (PrefixDecNode)node; + compileLHS(n.expr()); + as.subq(imm(n.expr().type().size()), reg(PTRREG)); + } +// FIXME + //} else if (node instanceof SuffixIncNode) { + //} else if (node instanceof SuffixDecNode) { + else { + throw new Error("wrong type for compileLHS"); + } + } + + protected void opAssignInit(AbstractAssignNode node) { + compile(node.rhs()); + as.movq(reg("ax"), reg("cx")); + loadWords(node.type(), node.lhs().address(), "ax"); + } + + protected void opAssignFini(AbstractAssignNode node) { + saveWords(node.type(), "ax", node.lhs().address()); + } + + public void visit(PlusAssignNode node) { + opAssignInit(node); + compile_plus(node.type()); + opAssignFini(node); + } + + public void visit(MinusAssignNode node) { + opAssignInit(node); + compile_minus(node.type()); + opAssignFini(node); + } + + public void visit(MulAssignNode node) { + opAssignInit(node); + compile_mul(node.type()); + opAssignFini(node); + } + + public void visit(DivAssignNode node) { + opAssignInit(node); + compile_div(node.type()); + opAssignFini(node); + } + + public void visit(ModAssignNode node) { + opAssignInit(node); + compile_mod(node.type()); + opAssignFini(node); + } + + public void visit(RShiftAssignNode node) { + opAssignInit(node); + compile_rshift(node.type()); + opAssignFini(node); + } + + public void visit(LShiftAssignNode node) { + opAssignInit(node); + compile_lshift(node.type()); + opAssignFini(node); + } + + public void visit(AndAssignNode node) { + opAssignInit(node); + compile_bitwiseand(node.type()); + opAssignFini(node); + } + + public void visit(OrAssignNode node) { + opAssignInit(node); + compile_bitwiseor(node.type()); + opAssignFini(node); + } + + public void visit(XorAssignNode node) { + opAssignInit(node); + compile_bitwisexor(node.type()); + opAssignFini(node); + } + + protected void binaryOpSetup(BinaryOpNode node) { + compile(node.right()); + as.pushq(reg("ax")); + compile(node.left()); + as.popq(reg("cx")); + } + + public void visit(PlusNode node) { + binaryOpSetup(node); + compile_plus(node.type()); + } + + public void visit(MinusNode node) { + binaryOpSetup(node); + compile_minus(node.type()); + } + + public void visit(MulNode node) { + binaryOpSetup(node); + compile_mul(node.type()); + } + + public void visit(DivNode node) { + binaryOpSetup(node); + compile_div(node.type()); + } + + public void visit(ModNode node) { + binaryOpSetup(node); + compile_mod(node.type()); + } + + public void visit(BitwiseAndNode node) { + binaryOpSetup(node); + compile_bitwiseand(node.type()); + } + + public void visit(BitwiseOrNode node) { + binaryOpSetup(node); + compile_bitwiseor(node.type()); + } + + public void visit(BitwiseXorNode node) { + binaryOpSetup(node); + compile_bitwisexor(node.type()); + } + + public void visit(RShiftNode node) { + binaryOpSetup(node); + compile_rshift(node.type()); + } + + public void visit(LShiftNode node) { + binaryOpSetup(node); + compile_lshift(node.type()); + } + + public void visit(EqNode node) { + binaryOpSetup(node); + compile_eq(node.type()); + } + + public void visit(NotEqNode node) { + binaryOpSetup(node); + compile_neq(node.type()); + } + + public void visit(GtNode node) { + binaryOpSetup(node); + compile_gt(node.type()); + } + + public void visit(LtNode node) { + binaryOpSetup(node); + compile_lt(node.type()); + } + + public void visit(GtEqNode node) { + binaryOpSetup(node); + compile_gteq(node.type()); + } + + public void visit(LtEqNode node) { + binaryOpSetup(node); + compile_lteq(node.type()); + } + + protected void compile_plus(Type t) { + as.add(t, reg("cx", t), reg("ax", t)); + } + + protected void compile_minus(Type t) { + as.sub(t, reg("cx", t), reg("ax", t)); + } + + protected void compile_mul(Type t) { + as.imul(t, reg("cx", t), reg("ax", t)); + } + + protected void compile_div(Type t) { + as.movq(imm(0), reg("dx")); + as.idiv(t, reg("cx", t)); + } + + protected void compile_mod(Type t) { + as.movq(imm(0), reg("dx")); + as.idiv(t, reg("cx", t)); + as.movq(reg("dx"), reg("ax")); + } + + protected void compile_bitwiseand(Type t) { + as.and(t, reg("cx", t), reg("ax", t)); + } + + protected void compile_bitwiseor(Type t) { + as.or(t, reg("cx", t), reg("ax", t)); + } + + protected void compile_bitwisexor(Type t) { + as.xor(t, reg("cx", t), reg("ax", t)); + } + + protected void compile_rshift(Type t) { + as.sar(t, register("cl"), reg("ax", t)); + } + + protected void compile_lshift(Type t) { + as.sal(t, register("cl"), reg("ax", t)); + } + + protected void compile_eq(Type t) { + as.cmp(t, reg("cx", t), reg("ax", t)); + as.sete(register("al")); + as.movzb(t, register("al"), reg("ax", t)); + } + + protected void compile_neq(Type t) { + as.cmp(t, reg("cx", t), reg("ax", t)); + as.setne(register("al")); + as.movzb(t, register("al"), reg("ax", t)); + } + + protected void compile_gt(Type t) { + as.cmp(t, reg("cx", t), reg("ax", t)); + as.setg(register("al")); + as.movzb(t, register("al"), reg("ax", t)); + } + + protected void compile_lt(Type t) { + as.cmp(t, reg("cx", t), reg("ax", t)); + as.setl(register("al")); + as.movzb(t, register("al"), reg("ax", t)); + } + + protected void compile_gteq(Type t) { + as.cmp(t, reg("cx", t), reg("ax", t)); + as.setge(register("al")); + as.movzb(t, register("al"), reg("ax", t)); + } + + protected void compile_lteq(Type t) { + as.cmp(t, reg("cx", t), reg("ax", t)); + as.setle(register("al")); + as.movzb(t, register("al"), reg("ax", t)); + } + + public void visit(UnaryPlusNode node) { + compile(node.expr()); + } + + public void visit(UnaryMinusNode node) { + compile(node.expr()); + as.neg(node.expr().type(), reg("ax", node.expr().type())); + } + + public void visit(LogicalNotNode node) { + compile(node.expr()); + testCond(node.expr().type(), "ax"); + as.sete(register("al")); + as.movzbl(register("al"), register("eax")); + } + + public void visit(BitwiseNotNode node) { + compile(node.expr()); + as.not(node.expr().type(), reg("ax", node.expr().type())); + } + + public void visit(PrefixIncNode node) { + Node e = node.expr(); + as.inc(e.type(), e.address()); + loadWords(e.type(), e.address(), "ax"); + } + + public void visit(PrefixDecNode node) { + Node e = node.expr(); + as.dec(e.type(), e.address()); + loadWords(e.type(), e.address(), "ax"); + } + + public void visit(SuffixIncNode node) { + Node e = node.expr(); + loadWords(e.type(), e.address(), "ax"); + as.inc(e.type(), e.address()); + } + + public void visit(SuffixDecNode node) { + Node e = node.expr(); + loadWords(e.type(), e.address(), "ax"); + as.dec(e.type(), e.address()); + } + + private void testCond(Type t, String regname) { + as.test(t, reg(regname, t), reg(regname, t)); + } + + public void visit(IfNode node) { + compile(node.cond()); + testCond(node.cond().type(), "ax"); + if (node.elseBody() != null) { + as.jz(node.elseLabel()); + compileStmt(node.thenBody()); + as.jmp(node.endLabel()); + as.label(node.elseLabel()); + compileStmt(node.elseBody()); + as.label(node.endLabel()); + } + else { + as.jz(node.endLabel()); + compileStmt(node.thenBody()); + as.label(node.endLabel()); + } + } + + public void visit(CondExprNode node) { + compile(node.cond()); + testCond(node.cond().type(), "ax"); + as.jz(node.elseLabel()); + compile(node.thenBody()); + as.jmp(node.endLabel()); + as.label(node.elseLabel()); + compile(node.elseBody()); + as.label(node.endLabel()); + } + + public void visit(SwitchNode node) { + compile(node.cond()); + Type t = typeTable.signedInt(); + Iterator cases = node.cases(); + while (cases.hasNext()) { + CaseNode caseNode = (CaseNode)cases.next(); + Iterator values = caseNode.values(); + while (values.hasNext()) { + as.movq(imm(caseValue((Node)values.next())), reg("cx")); + as.cmp(t, reg("cx", t), reg("ax", t)); + as.je(caseNode.beginLabel()); + } + } + cases = node.cases(); + while (cases.hasNext()) { + compile((CaseNode)cases.next()); + } + } + + protected long caseValue(Node node) { + if (!(node instanceof IntegerLiteralNode)) { + // FIXME: use exception + throw new Error("case accepts only integer literal"); + } + return ((IntegerLiteralNode)node).value(); + } + + public void visit(CaseNode node) { + as.label(node.beginLabel()); + compile(node.body()); + } + + public void visit(LogicalAndNode node) { + compile(node.left()); + testCond(node.left().type(), "ax"); + as.jz(node.endLabel()); + compile(node.right()); + as.label(node.endLabel()); + } + + public void visit(LogicalOrNode node) { + compile(node.left()); + testCond(node.left().type(), "ax"); + as.jnz(node.endLabel()); + compile(node.right()); + as.label(node.endLabel()); + } + + public void visit(WhileNode node) { + as.label(node.begLabel()); + compile(node.cond()); + testCond(node.cond().type(), "ax"); + as.jz(node.endLabel()); + compileStmt(node.body()); + as.jmp(node.begLabel()); + as.label(node.endLabel()); + } + + public void visit(DoWhileNode node) { + as.label(node.begLabel()); + compileStmt(node.body()); + as.label(node.continueLabel()); + compile(node.cond()); + testCond(node.cond().type(), "ax"); + as.jnz(node.begLabel()); + as.label(node.endLabel()); + } + + public void visit(ForNode node) { + compileStmt(node.init()); + as.label(node.begLabel()); + compile(node.cond()); + testCond(node.cond().type(), "ax"); + as.jz(node.endLabel()); + compileStmt(node.body()); + as.label(node.continueLabel()); + compileStmt(node.incr()); + as.jmp(node.begLabel()); + as.label(node.endLabel()); + } + + public void visit(BreakNode node) { + as.jmp(node.targetLabel()); + } + + public void visit(ContinueNode node) { + as.jmp(node.targetLabel()); + } + + public void visit(LabelNode node) { + as.label(node.label()); + compileStmt(node.stmt()); + } + + public void visit(GotoNode node) { + as.jmp(node.targetLabel()); + } + + /* + * x86 assembly DSL + */ + + protected Register reg(String name, Type type) { + return Register.forType(type, name); + } + + protected Register reg(String name) { + return Register.widestRegister(name); + } + + protected Register register(String name) { + return new Register(name); + } + + protected SimpleAddress addr(String regname) { + return new SimpleAddress(Register.widestRegister(regname)); + } + + protected CompositeAddress addr2(long offset, String regname) { + return new CompositeAddress(offset, Register.widestRegister(regname)); + } + + protected ImmediateValue imm(long n) { + return new ImmediateValue(n); + } + + protected Reference imm(Label label) { + return new Reference(label); + } + + protected void loadWords(Type type, AsmEntity addr, String reg) { + switch ((int)type.size()) { + case 1: + if (type.isSigned()) { // signed char + as.movsbl(addr, intReg(reg)); + } else { // unsigned char + as.movzbl(addr, intReg(reg)); + } + break; + case 2: + if (type.isSigned()) { // signed short + as.movswl(addr, intReg(reg)); + } else { // unsigned short + as.movzwl(addr, intReg(reg)); + } + break; + default: // int, long, long_long + as.mov(type, addr, reg(reg, type)); + break; + } + } + + protected Register intReg(String reg) { + return new Register("e" + reg); + } + + protected void saveWords(Type type, String reg, AsmEntity addr) { + as.mov(type, reg(reg, type), addr); + } +} diff --git a/net/loveruby/cflat/compiler/Compiler.java b/net/loveruby/cflat/compiler/Compiler.java new file mode 100644 index 0000000..2656122 --- /dev/null +++ b/net/loveruby/cflat/compiler/Compiler.java @@ -0,0 +1,156 @@ +package net.loveruby.cflat.compiler; +import net.loveruby.cflat.parser.*; +import net.loveruby.cflat.ast.*; +import net.loveruby.cflat.exception.*; +import java.util.*; +import java.io.*; + +public class Compiler { + static public void main(String[] args) { + new Compiler().commandMain(args); + } + + static final private String programId = "cbc"; + protected LibraryLoader loader; + protected ErrorHandler handler; + + public Compiler() { + loader = new LibraryLoader(); + handler = new ErrorHandler(programId); + } + + public Compiler(LibraryLoader ld, ErrorHandler h) { + loader = ld; + handler = h; + } + + public void commandMain(String[] args) { + try { + if (args.length == 0) errorExit("no argument given"); + if (args[0].equals("--dump-ast")) { + if (args.length != 2) + errorExit("no file input or too many files"); + dumpFile(args[1]); + } + else if (args[0].equals("--check-syntax")) { + if (args.length != 2) + errorExit("no file input or too many files"); + if (isValidSyntax(args[1])) { + System.out.println("Syntax OK"); + System.exit(0); + } else { + System.exit(1); + } + } + else { + if (args.length != 1) + errorExit("no file input or too many files"); + compileFile(args[0]); + } + } + catch (CompileException ex) { + System.exit(1); + } + } + + private void errorExit(String msg) { + handler.error(msg); + System.exit(1); + } + + public boolean isValidSyntax(String path) { + try { + parseFile(path); + return true; + } + catch (CompileException ex) { + return false; + } + } + + public void dumpFile(String path) throws CompileException { + parseFile(path).dump(""); + } + + public void compileFile(String path) throws CompileException { + AST ast = parseFile(path); + JumpResolver.resolve(ast, handler); + LocalReferenceResolver.resolve(ast, handler); + TypeResolver.resolve(ast); + String asm = CodeGenerator.generate(ast); + writeFile(asmFileName(path), asm); + assemble(asmFileName(path)); + } + + public AST parseFile(String path) throws CompileException { + return Parser.parseFile(new File(path), loader, handler); + } + + public void assemble(String path) throws IPCException { + String[] cmd = {"gcc", path, "-o", cmdFileName(path)}; + invoke(cmd); + } + + public void invoke(String[] cmd) throws IPCException { + try { + Process proc = Runtime.getRuntime().exec(cmd); + proc.waitFor(); + if (proc.exitValue() != 0) { + handler.error("gcc failed (assemble); status " + + proc.exitValue()); + throw new IPCException("compile error"); + } + } + catch (InterruptedException ex) { + handler.error("gcc interrupted: " + ex.getMessage()); + throw new IPCException("compile error"); + } + catch (IOException ex) { + handler.error(ex.getMessage()); + throw new IPCException("compile error"); + } + } + + protected void writeFile(String path, String str) + throws FileException { + try { + BufferedWriter f = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(path))); + try { + f.write(str); + } + finally { + f.close(); + } + } + catch (FileNotFoundException ex) { + handler.error("file not found: " + path); + throw new FileException("file error"); + } + catch (IOException ex) { + handler.error("IO error" + ex.getMessage()); + throw new FileException("file error"); + } + } + + protected String asmFileName(String orgPath) { + return baseName(orgPath, true) + ".s"; + } + + protected String cmdFileName(String orgPath) { + return baseName(orgPath, true); + } + + protected String baseName(String path) { + return new File(path).getName(); + } + + protected String baseName(String path, boolean stripExt) { + if (stripExt) { + return new File(path).getName().replaceFirst("\\.[^.]*$", ""); + } + else { + return baseName(path); + } + } +} diff --git a/net/loveruby/cflat/compiler/ErrorHandler.java b/net/loveruby/cflat/compiler/ErrorHandler.java new file mode 100644 index 0000000..89f4218 --- /dev/null +++ b/net/loveruby/cflat/compiler/ErrorHandler.java @@ -0,0 +1,33 @@ +package net.loveruby.cflat.compiler; +import java.io.*; + +public class ErrorHandler { + protected String programId; + protected PrintStream stream; + protected long nError; + protected long nWarning; + + public ErrorHandler(String progid) { + programId = progid; + stream = System.err; + } + + public ErrorHandler(String progid, OutputStream stream) { + programId = progid; + this.stream = new PrintStream(stream); + } + + public void error(String msg) { + stream.println(programId + ": error: " + msg); + nError++; + } + + public void warn(String msg) { + stream.println(programId + ": error: " + msg); + nWarning++; + } + + public boolean errorOccured() { + return (nError > 0); + } +} diff --git a/net/loveruby/cflat/compiler/JumpResolver.java b/net/loveruby/cflat/compiler/JumpResolver.java new file mode 100644 index 0000000..6b4cffe --- /dev/null +++ b/net/loveruby/cflat/compiler/JumpResolver.java @@ -0,0 +1,119 @@ +package net.loveruby.cflat.compiler; +import net.loveruby.cflat.ast.*; +import net.loveruby.cflat.asm.Label; +import net.loveruby.cflat.exception.*; +import java.util.*; + +public class JumpResolver extends Visitor { + static public void resolve(AST ast, ErrorHandler h) + throws SemanticException { + new JumpResolver(h).resolveAST(ast); + } + + protected ErrorHandler handler; + protected LinkedList breakTargetStack; + protected LinkedList continueTargetStack; + protected DefinedFunction currentFunction; + + public JumpResolver(ErrorHandler h) { + handler = h; + } + + public void resolveAST(AST ast) throws SemanticException { + breakTargetStack = new LinkedList(); + continueTargetStack = new LinkedList(); + Iterator funcs = ast.functions(); + while (funcs.hasNext()) { + currentFunction = (DefinedFunction)funcs.next(); + resolve(currentFunction.body()); + currentFunction.checkJumpLinks(handler); + } + if (handler.errorOccured()) { + throw new SemanticException("semantic error"); + } + } + + private BreakableStmt currentBreakTarget() + throws SemanticException { + if (breakTargetStack.isEmpty()) { + throw new SemanticException("break from out of while/for/switch"); + } + return (BreakableStmt)breakTargetStack.getLast(); + } + + private ContinueableStmt currentContinueTarget() + throws SemanticException { + if (continueTargetStack.isEmpty()) { + throw new SemanticException("continue from out of while/for"); + } + return (ContinueableStmt)continueTargetStack.getLast(); + } + + public void visit(SwitchNode node) { + resolve(node.cond()); + breakTargetStack.add(node); + resolveNodeList(node.cases()); + breakTargetStack.removeLast(); + } + + public void visit(WhileNode node) { + resolve(node.cond()); + breakTargetStack.add(node); + continueTargetStack.add(node); + resolve(node.body()); + continueTargetStack.removeLast(); + breakTargetStack.removeLast(); + } + + public void visit(DoWhileNode node) { + breakTargetStack.add(node); + continueTargetStack.add(node); + resolve(node.body()); + continueTargetStack.removeLast(); + breakTargetStack.removeLast(); + resolve(node.cond()); + } + + public void visit(ForNode node) { + resolve(node.init()); + resolve(node.cond()); + breakTargetStack.add(node); + continueTargetStack.add(node); + resolve(node.body()); + resolve(node.incr()); + continueTargetStack.removeLast(); + breakTargetStack.removeLast(); + } + + public void visit(BreakNode node) { + try { + node.setTargetLabel(currentBreakTarget().endLabel()); + } + catch (SemanticException ex) { + handler.error(ex.getMessage()); + } + } + + public void visit(ContinueNode node) { + try { + node.setTargetLabel(currentContinueTarget().continueLabel()); + } + catch (SemanticException ex) { + handler.error(ex.getMessage()); + } + } + + public void visit(LabelNode node) { + try { + Label label = currentFunction.defineLabel(node.name()); + node.setLabel(label); + } + catch (SemanticException ex) { + handler.error(ex.getMessage()); + } + } + + public void visit(GotoNode node) { + node.setTargetLabel(currentFunction.referLabel(node.target())); + } +} diff --git a/net/loveruby/cflat/compiler/LibraryLoader.java b/net/loveruby/cflat/compiler/LibraryLoader.java new file mode 100644 index 0000000..0af690b --- /dev/null +++ b/net/loveruby/cflat/compiler/LibraryLoader.java @@ -0,0 +1,51 @@ +package net.loveruby.cflat.compiler; +import net.loveruby.cflat.parser.*; +import net.loveruby.cflat.ast.Declarations; +import net.loveruby.cflat.exception.*; +import java.util.*; +import java.io.*; + +public class LibraryLoader { + protected List loadPath; + protected Map loadedLibrary; + + public LibraryLoader() { + loadPath = new ArrayList(); + loadPath.add("."); + loadedLibrary = new HashMap(); + } + + public LibraryLoader(List loadPath) { + this.loadPath = loadPath; + loadedLibrary = new HashMap(); + } + + public Declarations loadLibrary(String libid, ErrorHandler handler) + throws CompileException { + if (loadedLibrary.containsKey(libid)) { + return null; + } + Declarations decls = + Parser.parseDeclFile(searchLibrary(libid), this, handler); + loadedLibrary.put(libid, decls); + return decls; + } + + public File searchLibrary(String libid) throws FileException { + try { + Iterator pathes = loadPath.iterator(); + while (pathes.hasNext()) { + String path = (String)pathes.next(); + File file = new File(path + "/" + libid + ".hb"); + if (file.exists()) { + return file; + } + } + throw new FileException( + "no such library header file: " + libid); + } + catch (SecurityException ex) { + throw new FileException(ex.getMessage()); + } + } +} diff --git a/net/loveruby/cflat/compiler/LocalReferenceResolver.java b/net/loveruby/cflat/compiler/LocalReferenceResolver.java new file mode 100644 index 0000000..15250f7 --- /dev/null +++ b/net/loveruby/cflat/compiler/LocalReferenceResolver.java @@ -0,0 +1,117 @@ +package net.loveruby.cflat.compiler; +import net.loveruby.cflat.ast.*; +import net.loveruby.cflat.exception.*; +import java.util.*; + +public class LocalReferenceResolver extends Visitor { + static public void resolve(AST ast, ErrorHandler handler) + throws SemanticException { + new LocalReferenceResolver(handler).resolveAST(ast); + } + + protected ErrorHandler handler; + protected ToplevelScope toplevel; + protected LinkedList scopeStack; + protected ConstantTable constantTable; + + public LocalReferenceResolver(ErrorHandler handler) { + this.handler = handler; + } + + public void resolveAST(AST ast) throws SemanticException { + toplevel = ast.scope(); + scopeStack = new LinkedList(); + scopeStack.add(toplevel); + constantTable = ast.constantTable(); + + declareToplevelEntities(ast.declarations()); + defineToplevelEntities(ast.entities()); + resolveFunctions(ast.functions()); + toplevel.checkReferences(handler); + if (handler.errorOccured()) { + throw new SemanticException("compile error"); + } + } + + protected void declareToplevelEntities(Iterator funcdecls) { + while (funcdecls.hasNext()) { + toplevel.declare((UndefinedFunction)funcdecls.next()); + } + } + + protected void defineToplevelEntities(Iterator entities) { + while (entities.hasNext()) { + toplevel.define((Entity)entities.next()); + } + } + + protected void resolveFunctions(Iterator funcs) { + while (funcs.hasNext()) { + DefinedFunction func = (DefinedFunction)funcs.next(); + pushFrame(func.parameters()); + resolve(func.body()); + func.setFrame(popFrame()); + } + } + + protected void pushFrame(Iterator params) { + Frame frame = new Frame(toplevel); + while (params.hasNext()) { + Parameter param = (Parameter)params.next(); + if (frame.isDefinedLocally(param.name())) { + handler.error("duplicated parameter: " + param.name()); + } + else { + frame.allocateVariable(param); + } + } + scopeStack.addLast(frame); + } + + protected Frame popFrame() { + return (Frame)scopeStack.removeLast(); + } + + public void visit(BlockNode node) { + pushScope(node.variables()); + super.visit(node); + node.setScope(popScope()); + } + + protected void pushScope(Iterator vars) { + Scope scope = new Scope(currentScope()); + while (vars.hasNext()) { + Variable var = (Variable)vars.next(); + if (var.isPrivate()) { + scope.allocateStaticLocalVariable(var); + } + else { + scope.allocateVariable(var); + } + } + scopeStack.addLast(scope); + } + + protected Scope popScope() { + return (Scope)scopeStack.removeLast(); + } + + protected Scope currentScope() { + return (Scope)scopeStack.getLast(); + } + + public void visit(StringLiteralNode node) { + node.setEntry(constantTable.intern(node.value())); + } + + public void visit(VariableNode node) { + try { + Entity ent = currentScope().get(node.name()); + ent.refered(); + node.setEntity(ent); + } + catch (SemanticException ex) { + handler.error(ex.getMessage()); + } + } +} diff --git a/net/loveruby/cflat/compiler/TypeResolver.java b/net/loveruby/cflat/compiler/TypeResolver.java new file mode 100644 index 0000000..7111446 --- /dev/null +++ b/net/loveruby/cflat/compiler/TypeResolver.java @@ -0,0 +1,122 @@ +package net.loveruby.cflat.compiler; +import net.loveruby.cflat.ast.*; +import net.loveruby.cflat.type.*; +import java.util.*; + +public class TypeResolver extends Visitor implements DefinitionVisitor { + static public void resolve(AST ast) { + new TypeResolver().resolveProgram(ast); + } + + protected TypeTable typeTable; + + public void resolveProgram(AST ast) { + typeTable = ast.typeTable(); + //importLibraries(ast.importLibraryNames()); + defineTypes(ast.types()); + resolveDeclarations(ast.types()); + resolveDeclarations(ast.declarations()); + resolveDeclarations(ast.entities()); + typeTable.semanticCheck(); + } + + private void defineTypes(Iterator deftypes) { + while (deftypes.hasNext()) { + typeTable.define((TypeDefinition)deftypes.next()); + } + } + + private void bindType(TypeNode n) { + if (n.isResolved()) return; + n.setType(typeTable.get(n.typeRef())); + } + + private void resolveDeclarations(Iterator decls) { + while (decls.hasNext()) { + ((Declaration)decls.next()).accept(this); + } + } + + public void visit(StructNode struct) { + resolveComplexType(struct); + } + + public void visit(UnionNode union) { + resolveComplexType(union); + } + + public void resolveComplexType(ComplexTypeDefinition def) { + ComplexType ct = (ComplexType)typeTable.get(def.typeNode().typeRef()); + if (ct == null) { + throw new Error("FATAL: cannot intern Struct/Union"); + } + Iterator membs = ct.members(); + while (membs.hasNext()) { + Slot slot = (Slot)membs.next(); + bindType(slot.typeNode()); + } + } + + public void visit(TypedefNode typedef) { + bindType(typedef.typeNode()); + } + + public void visit(VariableNode n) { + bindType(n.typeNode()); + } + + public void visit(DefinedVariable var) { + bindType(var.typeNode()); + } + + public void visit(UndefinedVariable var) { + bindType(var.typeNode()); + } + + public void visit(DefinedFunction func) { + resolveFunctionHeader(func); + resolveLocalVariables(func); + resolve(func.body()); + } + + public void visit(UndefinedFunction func) { + resolveFunctionHeader(func); + } + + protected void resolveFunctionHeader(Function func) { + bindType(func.typeNode()); + Iterator params = func.parameters(); + while (params.hasNext()) { + Parameter param = (Parameter)params.next(); + bindType(param.typeNode()); + } + } + + protected void resolveLocalVariables(DefinedFunction func) { + Iterator vars = func.localVariables(); + while (vars.hasNext()) { + DefinedVariable var = (DefinedVariable)vars.next(); + bindType(var.typeNode()); + if (var.isInitialized()) { + resolve(var.initializer()); + } + } + } + + public void visit(CastNode node) { + bindType(node.typeNode()); + super.visit(node); + } + + public void visit(IntegerLiteralNode node) { + bindType(node.typeNode()); + } + + public void visit(CharacterLiteralNode node) { + bindType(node.typeNode()); + } + + public void visit(StringLiteralNode node) { + bindType(node.typeNode()); + } +} diff --git a/net/loveruby/cflat/compiler/Visitor.java b/net/loveruby/cflat/compiler/Visitor.java new file mode 100644 index 0000000..7c916db --- /dev/null +++ b/net/loveruby/cflat/compiler/Visitor.java @@ -0,0 +1,277 @@ +package net.loveruby.cflat.compiler; +import net.loveruby.cflat.ast.*; +import java.util.*; + +public class Visitor implements ASTVisitor { + protected void resolve(Node node) { + node.accept(this); + } + + protected void resolve2(Node l, Node r) { + resolve(l); + resolve(r); + } + + protected void resolveNodeList(Iterator ns) { + while (ns.hasNext()) { + Node n = (Node)ns.next(); + resolve(n); + } + } + + public void visit(BlockNode node) { + resolveNodeList(node.stmts()); + } + + public void visit(IfNode n) { + resolve(n.cond()); + resolve(n.thenBody()); + if (n.elseBody() != null) { + resolve(n.elseBody()); + } + } + + public void visit(CondExprNode n) { + resolve(n.cond()); + resolve(n.thenBody()); + if (n.elseBody() != null) { + resolve(n.elseBody()); + } + } + + public void visit(SwitchNode n) { + resolve(n.cond()); + resolveNodeList(n.cases()); + } + + public void visit(CaseNode n) { + resolveNodeList(n.values()); + resolve(n.body()); + } + + public void visit(WhileNode n) { + resolve(n.cond()); + resolve(n.body()); + } + + public void visit(DoWhileNode n) { + resolve(n.body()); + resolve(n.cond()); + } + + public void visit(ForNode n) { + resolve(n.init()); + resolve(n.cond()); + resolve(n.incr()); + resolve(n.body()); + } + + public void visit(BreakNode n) { + } + + public void visit(ContinueNode n) { + } + + public void visit(GotoNode n) { + } + + public void visit(LabelNode n) { + resolve(n.stmt()); + } + + public void visit(LogicalOrNode node) { + resolve2(node.left(), node.right()); + } + + public void visit(LogicalAndNode node) { + resolve2(node.left(), node.right()); + } + + public void visit(ReturnNode n) { + if (n.expr() != null) { + resolve(n.expr()); + } + } + + public void visit(AssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(PlusAssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(MinusAssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(MulAssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(DivAssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(ModAssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(AndAssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(OrAssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(XorAssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(LShiftAssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(RShiftAssignNode n) { + resolve2(n.lhs(), n.rhs()); + } + + public void visit(GtNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(LtNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(GtEqNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(LtEqNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(EqNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(NotEqNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(BitwiseOrNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(BitwiseXorNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(BitwiseAndNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(RShiftNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(LShiftNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(PlusNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(MinusNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(MulNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(DivNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(ModNode n) { + resolve2(n.left(), n.right()); + } + + public void visit(SuffixIncNode node) { + resolve(node.expr()); + } + + public void visit(SuffixDecNode node) { + resolve(node.expr()); + } + + public void visit(ArefNode node) { + resolve(node.expr()); + resolve(node.index()); + } + + public void visit(MemberNode node) { + resolve(node.expr()); + } + + public void visit(PtrMemberNode node) { + resolve(node.expr()); + } + + public void visit(IntegerLiteralNode node) { + } + + public void visit(CharacterLiteralNode node) { + } + + public void visit(StringLiteralNode node) { + } + + public void visit(FuncallNode node) { + resolve(node.expr()); + resolveNodeList(node.args()); + } + + public void visit(VariableNode node) { + } + + public void visit(UnaryPlusNode node) { + resolve(node.expr()); + } + + public void visit(UnaryMinusNode node) { + resolve(node.expr()); + } + + public void visit(LogicalNotNode node) { + resolve(node.expr()); + } + + public void visit(BitwiseNotNode node) { + resolve(node.expr()); + } + + public void visit(DereferenceNode node) { + resolve(node.expr()); + } + + public void visit(AddressNode node) { + resolve(node.expr()); + } + + public void visit(PrefixIncNode node) { + resolve(node.expr()); + } + + public void visit(PrefixDecNode node) { + resolve(node.expr()); + } + + public void visit(CastNode node) { + resolve(node.expr()); + } +} diff --git a/net/loveruby/cflat/exception/CompileException.java b/net/loveruby/cflat/exception/CompileException.java new file mode 100644 index 0000000..dd9f781 --- /dev/null +++ b/net/loveruby/cflat/exception/CompileException.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.exception; + +public class CompileException extends Exception { + public CompileException(String msg) { + super(msg); + } +} diff --git a/net/loveruby/cflat/exception/FileException.java b/net/loveruby/cflat/exception/FileException.java new file mode 100644 index 0000000..68384af --- /dev/null +++ b/net/loveruby/cflat/exception/FileException.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.exception; + +public class FileException extends CompileException { + public FileException(String msg) { + super(msg); + } +} diff --git a/net/loveruby/cflat/exception/IPCException.java b/net/loveruby/cflat/exception/IPCException.java new file mode 100644 index 0000000..5a929e2 --- /dev/null +++ b/net/loveruby/cflat/exception/IPCException.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.exception; + +public class IPCException extends CompileException { + public IPCException(String msg) { + super(msg); + } +} diff --git a/net/loveruby/cflat/exception/SemanticException.java b/net/loveruby/cflat/exception/SemanticException.java new file mode 100644 index 0000000..8ac1924 --- /dev/null +++ b/net/loveruby/cflat/exception/SemanticException.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.exception; + +public class SemanticException extends CompileException { + public SemanticException(String msg) { + super(msg); + } +} diff --git a/net/loveruby/cflat/exception/SyntaxException.java b/net/loveruby/cflat/exception/SyntaxException.java new file mode 100644 index 0000000..4749fea --- /dev/null +++ b/net/loveruby/cflat/exception/SyntaxException.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.exception; + +public class SyntaxException extends CompileException { + public SyntaxException(String msg) { + super(msg); + } +} diff --git a/net/loveruby/cflat/parser/Parser.jj b/net/loveruby/cflat/parser/Parser.jj new file mode 100644 index 0000000..d08e6e0 --- /dev/null +++ b/net/loveruby/cflat/parser/Parser.jj @@ -0,0 +1,1113 @@ +options { + STATIC = false; + UNICODE_INPUT = true; +} + +PARSER_BEGIN(Parser) +package net.loveruby.cflat.parser; +import net.loveruby.cflat.compiler.*; +import net.loveruby.cflat.ast.*; +import net.loveruby.cflat.type.*; +import net.loveruby.cflat.asm.*; +import net.loveruby.cflat.exception.*; +import java.lang.reflect.*; +import java.util.*; +import java.io.*; + +public class Parser { + static public AST parseFile(File file, + LibraryLoader loader, ErrorHandler handler) + throws CompileException { + return newFileParser(file, loader, handler).parse(); + } + + static public Declarations parseDeclFile(File file, + LibraryLoader loader, ErrorHandler handler) + throws CompileException { + return newFileParser(file, loader, handler).parseDecls(); + } + + static public Parser newFileParser(File file, + LibraryLoader loader, ErrorHandler handler) + throws FileException { + try { + return new Parser(newReader(new FileInputStream(file)), + file.getPath(), loader, handler); + } + catch (FileNotFoundException ex) { + throw new FileException(ex.getMessage()); + } + catch (UnsupportedEncodingException ex) { + throw new FileException(ex.getMessage()); + } + } + + static final protected String sourceEncoding = "UTF-8"; + + static protected Reader newReader(InputStream s) + throws UnsupportedEncodingException { + InputStreamReader r = new InputStreamReader(s, sourceEncoding); + return new BufferedReader(r); + } + + protected String sourceName; + protected LabelPool labelPool; + protected Set knownTypedefs; + protected LibraryLoader loader; + protected ErrorHandler handler; + + public Parser(Reader s, String name, + LibraryLoader loader, ErrorHandler handler) { + this(s); + this.sourceName = name; + this.loader = loader; + this.handler = handler; + this.labelPool = new LabelPool(); + this.knownTypedefs = new HashSet(); + } + + public AST parse() throws SyntaxException { + try { + return program(); + } + catch (TokenMgrError err) { + handler.error(err.getMessage()); + throw new SyntaxException(err.getMessage()); + } + catch (ParseException ex) { + handler.error(ex.getMessage()); + throw new SyntaxException(ex.getMessage()); + } + } + + public Declarations parseDecls() throws SyntaxException { + try { + return declfile(); + } + catch (TokenMgrError ex) { + handler.error(ex.getMessage()); + throw new SyntaxException(ex.getMessage()); + } + catch (ParseException ex) { + handler.error(ex.getMessage()); + throw new SyntaxException(ex.getMessage()); + } + } + + private void addType(String name) { + knownTypedefs.add(name); + } + + private boolean isType(String name) { + return knownTypedefs.contains(name); + } + + private IntegerLiteralNode integerNodeValue(String image) { + long i = integerValue(image); + if (image.endsWith("UL")) { + return new IntegerLiteralNode(new UnsignedLongRef(), i); + } else if (image.endsWith("L")) { + return new IntegerLiteralNode(new SignedLongRef(), i); + } else if (image.endsWith("U")) { + return new IntegerLiteralNode(new UnsignedIntRef(), i); + } else { + return new IntegerLiteralNode(new SignedIntRef(), i); + } + } + + private long integerValue(String image) { + String s = image.replaceFirst("[UL]+", ""); + if (s.startsWith("0x") || s.startsWith("0X")) { + return Long.parseLong(s.substring(2), 16); + } + else if (s.startsWith("0") && !s.equals("0")) { + return Long.parseLong(s.substring(1), 8); + } + else { + return Long.parseLong(s, 10); + } + } + + private long characterCode(String image) throws ParseException { + String s = stringValue(image); + if (s.length() != 1) { + throw new Error("must not happen: character length > 1"); + } + return (long)s.charAt(0); + } + + private String stringValue(String _image) throws ParseException { + int pos = 0; + int idx; + StringBuffer buf = new StringBuffer(); + String image = _image.substring(1, _image.length() - 1); + + while ((idx = image.indexOf("\\", pos)) >= 0) { + buf.append(image.substring(pos, idx)); + if (image.length() >= idx + 4 + && Character.isDigit(image.charAt(idx+1)) + && Character.isDigit(image.charAt(idx+2)) + && Character.isDigit(image.charAt(idx+3))) { + buf.append(unescapeOctal(image.substring(idx+1, idx+4))); + pos = idx + 4; + } + else { + buf.append(unescapeSeq(image.charAt(idx+1))); + pos = idx + 2; + } + } + if (pos < image.length()) { + buf.append(image.substring(pos, image.length())); + } + return buf.toString(); + } + + private static final int charMax = 255; + + private char unescapeOctal(String digits) throws ParseException { + int i = Integer.parseInt(digits, 8); + if (i > charMax) { + throw new ParseException( + "octal character sequence too big: \\" + digits); + } + return (char)i; + } + + private static final char bell = 7; + private static final char backspace = 8; + private static final char escape = 27; + private static final char vt = 11; + + private char unescapeSeq(char c) throws ParseException { + switch (c) { + case '0': return '\0'; + case '"': return '"'; + case '\'': return '\''; + case 'a': return bell; + case 'b': return backspace; + case 'e': return escape; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return vt; + default: + throw new ParseException("unknown escape sequence: \"\\" + c); + } + } +} +PARSER_END(Parser) + +/* + * Lexical Rules + */ + +// linear-white-spaces +SPECIAL_TOKEN: { <([" ","\t","\n","\r"])+> } + +// block comment +MORE: { "/*" : IN_BLOCK_COMMENT } + MORE: { <~[]> } + SKIP: { "*/" : DEFAULT } + +// line comment +SPECIAL_TOKEN: { + <"//" (~["\n","\r"])* ("\n" | "\r\n" | "\r")?> +} + +// reserved words +TOKEN: { + + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | + | +} + +// identifier +TOKEN: { + +} + +// integer literals +TOKEN: { + +} + +// character literal +MORE: { <"'"> : IN_CHARACTER } + MORE: { + <~["'","\\","\n","\r"]> + | <"\\" (["0"-"7"]){3}> + | <"\\" ~[]> +} + TOKEN: { : DEFAULT } + +// string literal +MORE: { <"\""> : IN_STRING } + MORE: { + <(~["\"","\\","\n","\r"])+> + | <"\\" (["0"-"7"]){3}> + | <"\\" ~[]> +} + TOKEN: { : DEFAULT } + +/* + * Grammar + */ + +Declarations declfile(): +{ + Declarations impdecls, decls = new Declarations(); + UndefinedFunction funcdecl; + UndefinedVariable vardecl; + StructNode defstruct; + UnionNode defunion; + TypedefNode typedef; +} +{ + impdecls=imports() + { + decls.add(impdecls); + } + ( LOOKAHEAD( typeref() "(") + funcdecl=funcdecl() { decls.addFuncdecl(funcdecl); } + | vardecl=vardecl() { decls.addVardecl(vardecl); } + | defstruct=defstruct() { decls.addDefstruct(defstruct); } + | defunion=defunion() { decls.addDefunion(defunion); } + | typedef=typedef() { decls.addTypedef(typedef); } + )* + + { + return decls; + } +} + +AST program(): +{ + Token t; + Declarations externs, decls; +} +{ + { + t = getToken(1); + } + externs=imports() decls=top_decls() + { + decls.add(externs); + return new AST(sourceName, decls, t); + } +} + +Declarations imports(): +{ + String libid; + Declarations libdecls = new Declarations(); +} +{ + (libid=import_stmt() + { + try { + Declarations decls = loader.loadLibrary(libid, handler); + if (decls != null) { + libdecls.add(decls); + Iterator types = decls.typedefs().iterator(); + while (types.hasNext()) { + TypedefNode n = (TypedefNode)types.next(); + addType(n.name()); + } + } + } + catch (CompileException ex) { + handler.error(ex.getMessage()); + throw new ParseException("compile error"); + } + } + )* + { + return libdecls; + } +} + +String import_stmt(): +{ String n; } +{ + n=name() ";" { return n; } +} + +Declarations top_decls(): +{ + Declarations decls = new Declarations(); + DefinedFunction defun; + List defvars; + StructNode defstruct; + UnionNode defunion; + TypedefNode typedef; +} +{ + ( LOOKAHEAD(storage() typeref() "(") + defun=defun() + { + decls.addDefun(defun); + } + | LOOKAHEAD(3) + defvars=defvars() + { + Iterator it = defvars.iterator(); + while (it.hasNext()) { + decls.addDefvar((DefinedVariable)it.next()); + } + } + | defstruct=defstruct() { decls.addDefstruct(defstruct); } + | defunion=defunion() { decls.addDefunion(defunion); } + | typedef=typedef() { decls.addTypedef(typedef); } + )* + { + return decls; + } +} + +List defvars(): +{ + List defs = new ArrayList(); + boolean priv; + TypeNode type; + String name; + Node init = null; +} +{ + priv=storage() type=type() name=name() ["=" init=rhs_expr()] + { + defs.add(new DefinedVariable(priv, type, name, init)); + init = null; + } + ("," name=name() ["=" init=rhs_expr()] + { + defs.add(new DefinedVariable(priv, type, name, init)); + init = null; + } + )* ";" + { + return defs; + } +} + +DefinedFunction defun(): +{ + boolean priv; + TypeRef ref; + String n; + Params ps; + Node body; +} +{ + priv=storage() ref=typeref() n=name() "(" ps=params() ")" body=block() + { + Params ptypes = ps.typeRefs(); + TypeNode t = new TypeNode(new PointerTypeRef( + new FunctionTypeRef(ref, ptypes))); + return new DefinedFunction(labelPool, priv, t, n, ps, body); + } +} + +boolean storage(): +{ Token t = null; } +{ + [t=] { return (t == null ? false : true); } +} + +Params params(): +{ FixedParams params; } +{ + LOOKAHEAD( ")") + + { + return new FixedParams(new ArrayList()); + } + | params=fixedparams() + ["," "..." { return new VarParams(params); }] + { + return params; + } +} + +FixedParams fixedparams(): +{ + List params = new ArrayList(); + Parameter param; +} +{ + param=param() { params.add(param); } + ( LOOKAHEAD(",", {!getToken(2).image.equals("...")}) + "," param=param() { params.add(param); } )* + { + return new FixedParams(params); + } +} + +Parameter param(): +{ + TypeNode t; + String n; +} +{ + t=type() n=name() { return new Parameter(t, n); } +} + +BlockNode block(): +{ + List list = new ArrayList(); + List vars; + List stmts; +} +{ + "{" (vars=defvars() { list.addAll(vars); })* stmts=stmts() "}" + { + return new BlockNode(list, stmts); + } +} + +StructNode defstruct(): +{ + String n; + List membs; +} +{ + n=name() membs=member_list() ";" + { + return new StructNode(new StructTypeRef(n), n, membs); + } +} + +UnionNode defunion(): +{ + String n; + List membs; +} +{ + n=name() membs=member_list() ";" + { + return new UnionNode(new UnionTypeRef(n), n, membs); + } +} + +List member_list(): +{ + List membs = new ArrayList(); + Slot s; +} +{ + "{" (s=slot() ";" { membs.add(s); })* "}" + { + return membs; + } +} + +Slot slot(): +{ + TypeNode t; + String n; +} +{ + t=type() n=name() { return new Slot(t, n); } +} + +UndefinedFunction funcdecl(): +{ + TypeRef ref; + String n; + Params ps; +} +{ + ref=typeref() n=name() "(" ps=params() ")" ";" + { + Params ptyperefs = ps.typeRefs(); + TypeNode t = new TypeNode(new PointerTypeRef( + new FunctionTypeRef(ref, ptyperefs))); + return new UndefinedFunction(t, n, ps); + } +} + +UndefinedVariable vardecl(): +{ + TypeNode t; + String n; +} +{ + t=type() n=name() ";" + { + return new UndefinedVariable(t, n); + } +} + +TypeNode type(): +{ TypeRef ref; } +{ + ref=typeref() { return new TypeNode(ref); } +} + +TypeRef typeref(): +{ + TypeRef ref; + Token t; + Params params; +} +{ + ref=typeref_base() + ( LOOKAHEAD(2) + "[" "]" + { + ref = new ArrayTypeRef(ref); + } + | "[" t= "]" + { + ref = new ArrayTypeRef(ref, integerValue(t.image)); + } + | "*" + { + ref = new PointerTypeRef(ref); + } + | "(" "*" ")" "(" params=param_typerefs() ")" + { + ref = new PointerTypeRef(new FunctionTypeRef(ref, params)); + } + )* + { + return ref; + } +} + +Params param_typerefs(): +{ FixedParams params; } +{ + LOOKAHEAD( ")") + + { + return new FixedParams(new ArrayList()); + } + | params=fixedparam_typerefs() + [ "," "..." { return new VarParams(params); } ] + { + return params; + } +} + +FixedParams fixedparam_typerefs(): +{ + List refs = new ArrayList(); + TypeRef ref; +} +{ + ref=typeref() { refs.add(ref); } + ( LOOKAHEAD(",", {!getToken(2).image.equals("...")}) + "," ref=typeref() { refs.add(ref); } )* + { + return new FixedParams(refs); + } +} + +TypeRef typeref_base(): +{ Token t; } +{ + { return new VoidTypeRef(); } + | { return new SignedCharRef(); } + | { return new SignedShortRef(); } + | { return new SignedIntRef(); } + | LOOKAHEAD(2) { return new SignedLongLongRef(); } + | { return new SignedLongRef(); } + | LOOKAHEAD(2) { return new UnsignedCharRef(); } + | LOOKAHEAD(2) { return new UnsignedShortRef(); } + | LOOKAHEAD(2) { return new UnsignedIntRef(); } + | LOOKAHEAD(3) + { return new UnsignedLongLongRef(); } + | LOOKAHEAD(2) + { return new UnsignedLongRef(); } + | t= + { return new StructTypeRef(t.image); } + | t= + { return new UnionTypeRef(t.image); } + | LOOKAHEAD({isType(getToken(1).image)}) t= + { return new UserTypeRef(t.image); } +} + +TypedefNode typedef(): +{ + TypeNode t; + Token newname; +} +{ + t=type() newname= ";" + { + addType(newname.image); + return new TypedefNode(t, newname.image); + } +} + +List stmts(): +{ + List ss = new ArrayList(); + Node s; +} +{ + (s=stmt() { if (s != null) ss.add(s); })* + { + return ss; + } +} + +Node stmt(): +{ Node n = null; } +{ + ( ";" + | LOOKAHEAD(2) n=labeled_stmt() + | n=expr() ";" + | n=block() + | n=if_stmt() + | n=while_stmt() + | n=dowhile_stmt() + | n=for_stmt() + | n=switch_stmt() + | n=break_stmt() + | n=continue_stmt() + | n=goto_stmt() + | n=return_stmt() + ) + { + return n; + } +} + +LabelNode labeled_stmt(): +{ + Token t; + Node n; +} +{ + t= ":" n=stmt() + { + return new LabelNode(t.image, n); + } +} + +IfNode if_stmt(): +{ Node cond, thenBody, elseBody = null; } +{ + "(" cond=expr() ")" thenBody=stmt() + [LOOKAHEAD(1) elseBody=stmt()] + { + return new IfNode(labelPool, cond, thenBody, elseBody); + } +} + +WhileNode while_stmt(): +{ Node cond, body; } +{ + "(" cond=expr() ")" body=stmt() + { + return new WhileNode(labelPool, cond, body); + } +} + +DoWhileNode dowhile_stmt(): +{ Node cond, body; } +{ + body=stmt() "(" cond=expr() ")" ";" + { + return new DoWhileNode(labelPool, body, cond); + } +} + +ForNode for_stmt(): +{ Node init = null, cond = null, incr = null, body; } +{ + "(" [init=expr()] ";" + [cond=expr()] ";" + [incr=expr()] ")" body=stmt() + { + return new ForNode(labelPool, init, cond, incr, body); + } +} + +SwitchNode switch_stmt(): +{ + Node cond; + List bodies; +} +{ + "(" cond=expr() ")" "{" bodies=case_clauses() "}" + { + return new SwitchNode(labelPool, cond, bodies); + } +} + +List case_clauses(): +{ + List clauses = new ArrayList(); + Node n; +} +{ + (n=case_clause() { clauses.add(n); })* + [n=default_clause() { clauses.add(n); }] + { + return clauses; + } +} + +CaseNode case_clause(): +{ + List values; + BlockNode body; +} +{ + values=cases() body=case_body() + { + return new CaseNode(labelPool, values, body); + } +} + +List cases(): +{ + List values = new ArrayList(); + Node n; +} +{ + ( n=primary() ":" { values.add(n); })+ + { + return values; + } +} + +CaseNode default_clause(): +{ BlockNode body; } +{ + ":" body=case_body() + { + return new CaseNode(labelPool, new ArrayList(), body); + } +} + +BlockNode case_body(): +{ + LinkedList ss = new LinkedList(); + Node s; +} +{ + (s=stmt() { if (s != null) ss.add(s); })+ + { + // last stmt of case clause must be break stmt. + if (! (ss.getLast() instanceof BreakNode)) { + throw new ParseException( + "missing break statement at the last of case clause"); + } + return new BlockNode(new ArrayList(), ss); + } +} + +GotoNode goto_stmt(): +{ Token t; } +{ + t= ";" { return new GotoNode(t.image); } +} + +BreakNode break_stmt(): {} +{ + ";" { return new BreakNode(); } +} + +ContinueNode continue_stmt(): {} +{ + ";" { return new ContinueNode(); } +} + +ReturnNode return_stmt(): +{ Node expr; } +{ + LOOKAHEAD(2) ";" { return new ReturnNode(null); } + | expr=expr() ";" { return new ReturnNode(expr); } +} + +Node expr(): +{ + Node l, r, n; + Class c; +} +{ + LOOKAHEAD(term() "=") + l=term() "=" r=rhs_expr() + { + return new AssignNode(l, r); + } + | LOOKAHEAD(term() opassign_op()) + l=term() c=opassign_op() r=expr() + { + try { + Constructor cons = + c.getConstructor(new Class[] {Node.class, Node.class}); + return (Node)cons.newInstance(new Object[] {l, r}); + } + catch (Exception ex) { + throw new Error("fatal: " + ex.getMessage()); + } + } + | n=expr9() + { + return n; + } +} + +Node rhs_expr(): +{ Node r; } +{ + r=composite_literal() { return r; } + | r=expr() { return r; } +} + +CompositeLiteralNode composite_literal(): +{ + List membs = new ArrayList(); + Node n; +} +{ + "{" [n=rhs_expr() { membs.add(n); } + ("," n=rhs_expr() { membs.add(n); })*] "}" + { + return new CompositeLiteralNode(membs); + } +} + +Class opassign_op(): {} +{ + ( "+=" { return PlusAssignNode.class; } + | "-=" { return MinusAssignNode.class; } + | "*=" { return MulAssignNode.class; } + | "/=" { return DivAssignNode.class; } + | "%=" { return ModAssignNode.class; } + | "&=" { return AndAssignNode.class; } + | "|=" { return OrAssignNode.class; } + | "^=" { return XorAssignNode.class; } + | "<<=" { return LShiftAssignNode.class; } + | ">>=" { return RShiftAssignNode.class; } + ) +} + +Node expr9(): +{ Node c, t, e; } +{ + c=expr8() ["?" t=expr9() ":" e=expr9() + { return new CondExprNode(labelPool, c, t, e); }] + { + return c; + } +} + +Node expr8(): +{ Node l, r; } +{ + l=expr7() ["||" r=expr8() { return new LogicalOrNode(labelPool, l, r); }] + { + return l; + } +} + +Node expr7(): +{ Node l, r; } +{ + l=expr6() ["&&" r=expr7() { return new LogicalAndNode(labelPool, l, r); }] + { + return l; + } +} + +Node expr6(): +{ Node l, r; } +{ + l=expr5() [( ">" r=expr6() { return new GtNode(l, r); } + | "<" r=expr6() { return new LtNode(l, r); } + | ">=" r=expr6() { return new GtEqNode(l, r); } + | "<=" r=expr6() { return new LtEqNode(l, r); } + | "==" r=expr6() { return new EqNode(l, r); } + | "!=" r=expr6() { return new NotEqNode(l, r); } )] + { + return l; + } +} + +Node expr5(): +{ Node l, r; } +{ + l=expr4() ["|" r=expr5() { return new BitwiseOrNode(l, r); }] + { + return l; + } +} + +Node expr4(): +{ Node l, r; } +{ + l=expr3() ["^" r=expr4() { return new BitwiseXorNode(l, r); }] + { + return l; + } +} + +Node expr3(): +{ Node l, r; } +{ + l=expr2() ["&" r=expr3() { return new BitwiseAndNode(l, r); }] + { + return l; + } +} + +Node expr2(): +{ Node l, r; } +{ + l=expr1() [( ">>" r=expr2() { return new RShiftNode(l, r); } + | "<<" r=expr2() { return new LShiftNode(l, r); } )] + { + return l; + } +} + +Node expr1(): +{ Node l, r; } +{ + l=expr0() [( "+" r=expr1() { return new PlusNode(l, r); } + | "-" r=expr1() { return new MinusNode(l, r); } )] + { + return l; + } +} + +Node expr0(): +{ Node l, r; } +{ + l=term() [( "*" r=expr0() { return new MulNode(l, r); } + | "/" r=expr0() { return new DivNode(l, r); } + | "%" r=expr0() { return new ModNode(l, r); } )] + { + return l; + } +} + +Node term(): +{ + TypeNode t; + Node n; +} +{ + LOOKAHEAD("(" type()) + "(" t=type() ")" n=term() { return new CastNode(t, n); } + | n=unary() { return n; } +} + +Node unary(): +{ + Node n; +} +{ + "++" n=unary() { return new PrefixIncNode(n); } + | "--" n=unary() { return new PrefixDecNode(n); } + | "+" n=term() { return new UnaryPlusNode(n); } + | "-" n=term() { return new UnaryMinusNode(n); } + | "!" n=term() { return new LogicalNotNode(n); } + | "~" n=term() { return new BitwiseNotNode(n); } + | "*" n=term() { return new DereferenceNode(n); } + | "&" n=term() { return new AddressNode(n); } + | n=postfix() { return n; } +} + +Node postfix(): +{ + Node base, idx; + String memb; + List args; +} +{ + base=primary() + ( "++" { base = new SuffixIncNode(base); } + | "--" { base = new SuffixDecNode(base); } + | "[" idx=expr() "]" { base = new ArefNode(base, idx); } + | "." memb=name() { base = new MemberNode(base, memb); } + | "->" memb=name() { base = new PtrMemberNode(base, memb); } + | "(" args=args() ")" { base = new FuncallNode(base, args); } + )* + { + return base; + } +} + +String name(): +{ Token t; } +{ + t= { return t.image; } +} + +List args(): +{ + List args = new ArrayList(); + Node arg; +} +{ + [ LOOKAHEAD({!getToken(1).image.equals(")")}) + arg=expr() { args.add(arg); } + ("," arg=expr() { args.add(arg); })* ] + { + return args; + } +} + +Node primary(): +{ + Token t; + Node n; +} +{ + t= + { + return integerNodeValue(t.image); + } + | t= + { + return new CharacterLiteralNode(new SignedCharRef(), + characterCode(t.image)); + } + | t= + { + return new StringLiteralNode( + new PointerTypeRef(new SignedCharRef()), + stringValue(t.image)); + } + | t= + { + return new VariableNode(t.image); + } + | "(" n=expr() ")" + { + return n; + } +} diff --git a/net/loveruby/cflat/type/ArrayType.java b/net/loveruby/cflat/type/ArrayType.java new file mode 100644 index 0000000..6c73e78 --- /dev/null +++ b/net/loveruby/cflat/type/ArrayType.java @@ -0,0 +1,49 @@ +package net.loveruby.cflat.type; + +public class ArrayType extends Type { + protected Type base; + protected long length; + + public ArrayType(Type t) { + base = t; + length = -1; + } + + public ArrayType(Type t, long len) { + base = t; + length = len; + } + + public Type base() { + return base; + } + + public long length() { + return length; + } + + public long size() { + // platform dependent: take alignment into account + return base.size() * length; + } + + public boolean isReferable() { + return true; + } + + public boolean isAllocated() { + return (length >= 0); + } + + public boolean isArray() { + return true; + } + + public String textize() { + if (length < 0) { + return base.textize() + "[]"; + } else { + return base.textize() + "[" + length + "]"; + } + } +} diff --git a/net/loveruby/cflat/type/ArrayTypeRef.java b/net/loveruby/cflat/type/ArrayTypeRef.java new file mode 100644 index 0000000..c87abe6 --- /dev/null +++ b/net/loveruby/cflat/type/ArrayTypeRef.java @@ -0,0 +1,42 @@ +package net.loveruby.cflat.type; + +public class ArrayTypeRef extends TypeRef { + protected TypeRef base; + protected long length; + static final protected long undefined = -1; + + public ArrayTypeRef(TypeRef base) { + this(base, undefined); + } + + public ArrayTypeRef(TypeRef ref, long len) { + if (len < 0) throw new Error("negative array length"); + base = ref; + length = len; + } + + public boolean isArrayTypeRef() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof ArrayTypeRef) && + (length == ((ArrayTypeRef)other).length); + } + + public int hashCode() { + return (1 << 10) & (int)length; + } + + public TypeRef base() { + return base; + } + + public long length() { + return length; + } + + public boolean isLengthUndefined() { + return (length == undefined); + } +} diff --git a/net/loveruby/cflat/type/ComplexType.java b/net/loveruby/cflat/type/ComplexType.java new file mode 100644 index 0000000..7726b26 --- /dev/null +++ b/net/loveruby/cflat/type/ComplexType.java @@ -0,0 +1,79 @@ +package net.loveruby.cflat.type; +import net.loveruby.cflat.ast.Slot; +import net.loveruby.cflat.type.*; +import java.util.*; + +abstract public class ComplexType extends Type { + protected String name; + protected List members; + protected long size; + protected boolean isRecursiveChecked; + + public ComplexType(String n, List membs) { + name = n; + members = membs; + size = Type.sizeUnknown; + isRecursiveChecked = false; + } + + public String name() { + return name; + } + + public long size() { + if (size == Type.sizeUnknown) { + computeOffsets(); + } + return size; + } + + public Iterator members() { + return members.iterator(); + } + + public Type memberType(String name) { + return fetch(name).type(); + } + + public long memberOffset(String name) { + Slot s = fetch(name); + if (s.offset() == Type.sizeUnknown) { + computeOffsets(); + } + return s.offset(); + } + + abstract protected void computeOffsets(); + + protected long align(long n) { + // platform dependent + return n; + } + + protected Slot fetch(String name) { + Slot s = get(name); + if (s == null) { + throw new Error("no such member in " + textize() + ": " + name); + } + return s; + } + + public Slot get(String name) { + Iterator membs = members.iterator(); + while (membs.hasNext()) { + Slot s = (Slot)membs.next(); + if (s.name().equals(name)) { + return s; + } + } + return null; + } + + public boolean isRecursiveChecked() { + return isRecursiveChecked; + } + + public void recursiveChecked() { + isRecursiveChecked = true; + } +} diff --git a/net/loveruby/cflat/type/FunctionType.java b/net/loveruby/cflat/type/FunctionType.java new file mode 100644 index 0000000..583e93e --- /dev/null +++ b/net/loveruby/cflat/type/FunctionType.java @@ -0,0 +1,46 @@ +package net.loveruby.cflat.type; +import net.loveruby.cflat.ast.Params; +import java.util.*; + +public class FunctionType extends Type { + protected Type returnType; + protected Params paramTypes; + + public FunctionType(Type ret, Params partypes) { + returnType = ret; + paramTypes = partypes; + } + + public Type returnType() { + return returnType; + } + + public boolean isVararg() { + return paramTypes.isVararg(); + } + + public boolean isFunction() { + return true; + } + + public long alignment() { + throw new Error("FunctionType#alignment called"); + } + + public long size() { + throw new Error("FunctionType#size called"); + } + + public String textize() { + StringBuffer buf = new StringBuffer(); + buf.append(returnType.textize()); + buf.append(" (*)("); + Iterator params = paramTypes.parameters(); + while (params.hasNext()) { + Type t = (Type)params.next(); + buf.append(t.textize()); + } + buf.append(")"); + return buf.toString(); + } +} diff --git a/net/loveruby/cflat/type/FunctionTypeRef.java b/net/loveruby/cflat/type/FunctionTypeRef.java new file mode 100644 index 0000000..fb1de5b --- /dev/null +++ b/net/loveruby/cflat/type/FunctionTypeRef.java @@ -0,0 +1,36 @@ +package net.loveruby.cflat.type; +import net.loveruby.cflat.ast.*; +import java.util.*; + +public class FunctionTypeRef extends TypeRef { + protected TypeRef returnType; + protected Params params; + + public FunctionTypeRef(TypeRef returnType, Params params) { + this.returnType = returnType; + this.params = params; + } + + public boolean isFunctionTypeRef() { + return true; + } + + public boolean equals(Object other) { + if (!(other instanceof FunctionTypeRef)) return false; + FunctionTypeRef ref = (FunctionTypeRef)other; + return returnType.equals(ref.returnType()) && + params.equals(ref.params()); + } + + public int hashCode() { + return (1 << 13) ^ returnType.hashCode(); + } + + public TypeRef returnType() { + return returnType; + } + + public Params params() { + return params; + } +} diff --git a/net/loveruby/cflat/type/IntegerType.java b/net/loveruby/cflat/type/IntegerType.java new file mode 100644 index 0000000..a5a3a6c --- /dev/null +++ b/net/loveruby/cflat/type/IntegerType.java @@ -0,0 +1,33 @@ +package net.loveruby.cflat.type; + +public class IntegerType extends Type { + protected long size; + protected boolean signed; + protected String name; + + public IntegerType(long sz, boolean sign, String nm) { + size = sz; + signed = sign; + name = nm; + } + + public long size() { + return size; + } + + public boolean isInteger() { + return true; + } + + public boolean isNumeric() { + return true; + } + + public boolean isSigned() { + return signed; + } + + public String textize() { + return name; + } +} diff --git a/net/loveruby/cflat/type/PointerType.java b/net/loveruby/cflat/type/PointerType.java new file mode 100644 index 0000000..d74bb87 --- /dev/null +++ b/net/loveruby/cflat/type/PointerType.java @@ -0,0 +1,45 @@ +package net.loveruby.cflat.type; + +public class PointerType extends Type { + protected long size; + protected Type base; + + public PointerType(long s, Type t) { + size = s; + base = t; + } + + public long size() { + return size; + } + + public Type base() { + return base; + } + + public boolean isReferable() { + return true; + } + + public boolean isAllocated() { + return true; + } + + public boolean isInteger() { + return true; + } + + public boolean isNumeric() { + return true; + } + + public boolean isPointer() { + return true; + } + + //public boolean isArray() { return true; } + + public String textize() { + return base.textize() + "*"; + } +} diff --git a/net/loveruby/cflat/type/PointerTypeRef.java b/net/loveruby/cflat/type/PointerTypeRef.java new file mode 100644 index 0000000..befd7a1 --- /dev/null +++ b/net/loveruby/cflat/type/PointerTypeRef.java @@ -0,0 +1,26 @@ +package net.loveruby.cflat.type; + +public class PointerTypeRef extends TypeRef { + protected TypeRef base; + + public PointerTypeRef(TypeRef ref) { + base = ref; + } + + public boolean isPointer() { + return true; + } + + public TypeRef base() { + return base; + } + + public boolean equals(Object other) { + return (other instanceof PointerTypeRef) && + base.equals(((PointerTypeRef)other).base); + } + + public int hashCode() { + return (1 << 11) & base.hashCode(); + } +} diff --git a/net/loveruby/cflat/type/SignedCharRef.java b/net/loveruby/cflat/type/SignedCharRef.java new file mode 100644 index 0000000..bd3a4b1 --- /dev/null +++ b/net/loveruby/cflat/type/SignedCharRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class SignedCharRef extends TypeRef { + public SignedCharRef() { + } + + public boolean isSignedChar() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof SignedCharRef); + } + + public int hashCode() { + return 0; + } +} diff --git a/net/loveruby/cflat/type/SignedCharType.java b/net/loveruby/cflat/type/SignedCharType.java new file mode 100644 index 0000000..4722571 --- /dev/null +++ b/net/loveruby/cflat/type/SignedCharType.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.type; + +public class SignedCharType extends IntegerType { + public SignedCharType(int size) { + super(size, true, "char"); + } +} diff --git a/net/loveruby/cflat/type/SignedIntRef.java b/net/loveruby/cflat/type/SignedIntRef.java new file mode 100644 index 0000000..f4a80ab --- /dev/null +++ b/net/loveruby/cflat/type/SignedIntRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class SignedIntRef extends TypeRef { + public SignedIntRef() { + } + + public boolean isSignedInt() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof SignedIntRef); + } + + public int hashCode() { + return 2; + } +} diff --git a/net/loveruby/cflat/type/SignedIntType.java b/net/loveruby/cflat/type/SignedIntType.java new file mode 100644 index 0000000..ac438dd --- /dev/null +++ b/net/loveruby/cflat/type/SignedIntType.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.type; + +public class SignedIntType extends IntegerType { + public SignedIntType(int size) { + super(size, true, "int"); + } +} diff --git a/net/loveruby/cflat/type/SignedLongLongRef.java b/net/loveruby/cflat/type/SignedLongLongRef.java new file mode 100644 index 0000000..a061c65 --- /dev/null +++ b/net/loveruby/cflat/type/SignedLongLongRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class SignedLongLongRef extends TypeRef { + public SignedLongLongRef() { + } + + public boolean isSignedLongLong() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof SignedLongLongRef); + } + + public int hashCode() { + return -2; + } +} diff --git a/net/loveruby/cflat/type/SignedLongLongType.java b/net/loveruby/cflat/type/SignedLongLongType.java new file mode 100644 index 0000000..2d720ee --- /dev/null +++ b/net/loveruby/cflat/type/SignedLongLongType.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.type; + +public class SignedLongLongType extends IntegerType { + public SignedLongLongType(int size) { + super(size, true, "long_long"); + } +} diff --git a/net/loveruby/cflat/type/SignedLongRef.java b/net/loveruby/cflat/type/SignedLongRef.java new file mode 100644 index 0000000..0e767ac --- /dev/null +++ b/net/loveruby/cflat/type/SignedLongRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class SignedLongRef extends TypeRef { + public SignedLongRef() { + } + + public boolean isSignedLong() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof SignedLongRef); + } + + public int hashCode() { + return 3; + } +} diff --git a/net/loveruby/cflat/type/SignedLongType.java b/net/loveruby/cflat/type/SignedLongType.java new file mode 100644 index 0000000..270a7cc --- /dev/null +++ b/net/loveruby/cflat/type/SignedLongType.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.type; + +public class SignedLongType extends IntegerType { + public SignedLongType(int size) { + super(size, true, "long"); + } +} diff --git a/net/loveruby/cflat/type/SignedShortRef.java b/net/loveruby/cflat/type/SignedShortRef.java new file mode 100644 index 0000000..99e5a1e --- /dev/null +++ b/net/loveruby/cflat/type/SignedShortRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class SignedShortRef extends TypeRef { + public SignedShortRef() { + } + + public boolean isSignedShort() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof SignedShortRef); + } + + public int hashCode() { + return 1; + } +} diff --git a/net/loveruby/cflat/type/SignedShortType.java b/net/loveruby/cflat/type/SignedShortType.java new file mode 100644 index 0000000..8a9b6b0 --- /dev/null +++ b/net/loveruby/cflat/type/SignedShortType.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.type; + +public class SignedShortType extends IntegerType { + public SignedShortType(int size) { + super(size, true, "short"); + } +} diff --git a/net/loveruby/cflat/type/StructType.java b/net/loveruby/cflat/type/StructType.java new file mode 100644 index 0000000..f3c548b --- /dev/null +++ b/net/loveruby/cflat/type/StructType.java @@ -0,0 +1,36 @@ +package net.loveruby.cflat.type; +import net.loveruby.cflat.ast.Slot; +import java.util.*; + +public class StructType extends ComplexType { + public StructType(String name, List membs) { + super(name, membs); + } + + public long alignment() { + if (members.isEmpty()) { + return 0; + } else { + return ((Type)members.get(0)).alignment(); + } + } + + public boolean isStruct() { + return true; + } + + protected void computeOffsets() { + long offset = 0; + Iterator membs = members(); + while (membs.hasNext()) { + Slot s = (Slot)membs.next(); + s.setOffset(offset); + offset = align(offset + s.size()); + } + size = offset; + } + + public String textize() { + return "struct " + name; + } +} diff --git a/net/loveruby/cflat/type/StructTypeRef.java b/net/loveruby/cflat/type/StructTypeRef.java new file mode 100644 index 0000000..8826e10 --- /dev/null +++ b/net/loveruby/cflat/type/StructTypeRef.java @@ -0,0 +1,26 @@ +package net.loveruby.cflat.type; + +public class StructTypeRef extends TypeRef { + protected String name; + + public StructTypeRef(String n) { + name = n; + } + + public boolean isStruct() { + return true; + } + + public boolean equals(Object other) { + if (!(other instanceof StructTypeRef)) return false; + return name.equals(((StructTypeRef)other).name); + } + + public int hashCode() { + return 8 ^ name.hashCode(); + } + + public String name() { + return name; + } +} diff --git a/net/loveruby/cflat/type/Type.java b/net/loveruby/cflat/type/Type.java new file mode 100644 index 0000000..3812114 --- /dev/null +++ b/net/loveruby/cflat/type/Type.java @@ -0,0 +1,61 @@ +package net.loveruby.cflat.type; + +public abstract class Type { + static final public long sizeUnknown = -1; + + public long alignment() { + return size(); + } + + public abstract long size(); + + public boolean isReferable() { + return false; + } + + public boolean isVoid() { + return false; + } + + public boolean isInt() { + return false; + } + + public boolean isInteger() { + return false; + } + + public boolean isSigned() { + throw new Error("#isSigned for non-integer type"); + } + + public boolean isNumeric() { + return false; + } + + public boolean isPointer() { + return false; + } + + public boolean isArray() { + return false; + } + + public boolean isStruct() { + return false; + } + + public boolean isUnion() { + return false; + } + + public boolean isUserType() { + return false; + } + + public boolean isFunction() { + return false; + } + + public abstract String textize(); +} diff --git a/net/loveruby/cflat/type/TypeRef.java b/net/loveruby/cflat/type/TypeRef.java new file mode 100644 index 0000000..155b977 --- /dev/null +++ b/net/loveruby/cflat/type/TypeRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public abstract class TypeRef { + public boolean isSignedChar() { return false; } + public boolean isSignedShort() { return false; } + public boolean isSignedInt() { return false; } + public boolean isSignedLong() { return false; } + public boolean isUnsignedChar() { return false; } + public boolean isUnsignedShort() { return false; } + public boolean isUnsignedInt() { return false; } + public boolean isUnsignedLong() { return false; } + public boolean isArray() { return false; } + public boolean isPointer() { return false; } + public boolean isStruct() { return false; } + public boolean isUnion() { return false; } + public boolean isUserType() { return false; } + public boolean isFunctionType() { return false; } +} diff --git a/net/loveruby/cflat/type/TypeTable.java b/net/loveruby/cflat/type/TypeTable.java new file mode 100644 index 0000000..6050f22 --- /dev/null +++ b/net/loveruby/cflat/type/TypeTable.java @@ -0,0 +1,163 @@ +package net.loveruby.cflat.type; +import net.loveruby.cflat.ast.TypeNode; +import net.loveruby.cflat.ast.TypeDefinition; +import net.loveruby.cflat.ast.Slot; +import java.util.*; + +public class TypeTable { + static public TypeTable ilp32() { return newTable(1, 2, 4, 4, 8, 4); } + static public TypeTable ilp64() { return newTable(1, 2, 8, 8, 8, 8); } + static public TypeTable lp64() { return newTable(1, 2, 4, 8, 8, 8); } + static public TypeTable llp64() { return newTable(1, 2, 4, 4, 8, 8); } + + static protected final TypeRef voidTypeRef = new VoidTypeRef(); + static protected final TypeRef signedCharRef = new SignedCharRef(); + static protected final TypeRef signedShortRef = new SignedShortRef(); + static protected final TypeRef signedIntRef = new SignedIntRef(); + static protected final TypeRef signedLongRef = new SignedLongRef(); + static protected final TypeRef signedLongLongRef = new SignedLongLongRef(); + static protected final TypeRef unsignedCharRef = new UnsignedCharRef(); + static protected final TypeRef unsignedShortRef = new UnsignedShortRef(); + static protected final TypeRef unsignedIntRef = new UnsignedIntRef(); + static protected final TypeRef unsignedLongRef = new UnsignedLongRef(); + static protected final TypeRef unsignedLongLongRef = new UnsignedLongLongRef(); + + static private TypeTable newTable(int charsize, int shortsize, + int intsize, int longsize, int longlongsize, int ptrsize) { + TypeTable table = new TypeTable(ptrsize); + table.put(voidTypeRef, new VoidType()); + table.put(signedCharRef, new SignedCharType(charsize)); + table.put(signedShortRef, new SignedShortType(shortsize)); + table.put(signedIntRef, new SignedIntType(intsize)); + table.put(signedLongRef, new SignedLongType(longsize)); + table.put(signedLongLongRef, new SignedLongType(longlongsize)); + table.put(unsignedCharRef, new UnsignedCharType(charsize)); + table.put(unsignedShortRef, new UnsignedShortType(shortsize)); + table.put(unsignedIntRef, new UnsignedIntType(intsize)); + table.put(unsignedLongRef, new UnsignedLongType(longsize)); + table.put(unsignedLongLongRef, new UnsignedLongLongType(longlongsize)); + return table; + } + + protected int pointerSize; + protected Map table; + + public TypeTable(int ptrsize) { + pointerSize = ptrsize; + table = new HashMap(); + } + + public void put(TypeRef ref, Type t) { + table.put(ref, t); + } + + public Type get(TypeRef ref) { + Type type = (Type)table.get(ref); + if (type == null) { + if (ref instanceof PointerTypeRef) { + PointerTypeRef pref = (PointerTypeRef)ref; + Type t = new PointerType(pointerSize, get(pref.base())); + table.put(pref, t); + return t; + } + else if (ref instanceof ArrayTypeRef) { + ArrayTypeRef aref = (ArrayTypeRef)ref; + Type t = new ArrayType(get(aref.base()), aref.length()); + table.put(aref, t); + return t; + } + else if (ref instanceof FunctionTypeRef) { + FunctionTypeRef fref = (FunctionTypeRef)ref; + Type t = new FunctionType(get(fref.returnType()), + fref.params().internTypes(this)); + table.put(fref, t); + return t; + } + throw new Error("unregistered type: " + ref.toString()); + } + return type; + } + + public Iterator types() { + return table.values().iterator(); + } + + public SignedCharType signedChar() { + return (SignedCharType)table.get(signedCharRef); + } + + public SignedShortType signedShort() { + return (SignedShortType)table.get(signedShortRef); + } + + public SignedIntType signedInt() { + return (SignedIntType)table.get(signedIntRef); + } + + public SignedLongType signedLong() { + return (SignedLongType)table.get(signedLongRef); + } + + public UnsignedCharType unsignedChar() { + return (UnsignedCharType)table.get(unsignedCharRef); + } + + public UnsignedShortType unsignedShort() { + return (UnsignedShortType)table.get(unsignedShortRef); + } + + public UnsignedIntType unsignedInt() { + return (UnsignedIntType)table.get(unsignedIntRef); + } + + public UnsignedLongType unsignedLong() { + return (UnsignedLongType)table.get(unsignedLongRef); + } + + public void define(TypeDefinition t) { + t.defineIn(this); + } + + public void defineStruct(StructTypeRef ref, List membs) { + table.put(ref, new StructType(ref.name(), membs)); + } + + public void defineUnion(UnionTypeRef ref, List membs) { + table.put(ref, new UnionType(ref.name(), membs)); + } + + public void defineUserType(UserTypeRef ref, TypeNode real) { + table.put(ref, new UserType(ref.name(), real)); + } + + public void semanticCheck() { + Iterator types = table.values().iterator(); + while (types.hasNext()) { + Type t = (Type)types.next(); + if (t instanceof ComplexType) { + checkRecursiveDefinition((ComplexType)t); + } + } + } + + protected void checkRecursiveDefinition(ComplexType t) { + checkRecursiveDefinition(t, new HashMap()); + } + + protected void checkRecursiveDefinition(ComplexType t, Map lock) { + if (lock.containsKey(t)) { // FIXME: use exception + throw new Error("recursive type definition: " + t.textize()); + } + if (t.isRecursiveChecked()) return; + lock.put(t, t); + Iterator membs = t.members(); + while (membs.hasNext()) { + Slot slot = (Slot)membs.next(); + if (slot.type() instanceof ComplexType) { + checkRecursiveDefinition((ComplexType)slot.type(), lock); + } + } + lock.remove(t); + t.recursiveChecked(); + } +} diff --git a/net/loveruby/cflat/type/UnionType.java b/net/loveruby/cflat/type/UnionType.java new file mode 100644 index 0000000..4450575 --- /dev/null +++ b/net/loveruby/cflat/type/UnionType.java @@ -0,0 +1,35 @@ +package net.loveruby.cflat.type; +import net.loveruby.cflat.ast.Slot; +import java.util.*; + +public class UnionType extends ComplexType { + public UnionType(String name, List membs) { + super(name, membs); + } + + public long alignmemt() { + // platform depedent + return 1; + } + + protected void computeOffsets() { + long max = 0; + Iterator membs = members.iterator(); + while (membs.hasNext()) { + Slot s = (Slot)membs.next(); + s.setOffset(0); + if (align(s.size()) > max) { + max = align(s.size()); + } + } + size = max; + } + + public boolean isUnion() { + return true; + } + + public String textize() { + return "union " + name; + } +} diff --git a/net/loveruby/cflat/type/UnionTypeRef.java b/net/loveruby/cflat/type/UnionTypeRef.java new file mode 100644 index 0000000..d01ebf1 --- /dev/null +++ b/net/loveruby/cflat/type/UnionTypeRef.java @@ -0,0 +1,26 @@ +package net.loveruby.cflat.type; + +public class UnionTypeRef extends TypeRef { + protected String name; + + public UnionTypeRef(String n) { + name = n; + } + + public boolean isUnion() { + return true; + } + + public boolean equals(Object other) { + if (!(other instanceof UnionTypeRef)) return false; + return name.equals(((UnionTypeRef)other).name); + } + + public int hashCode() { + return 9 ^ name.hashCode(); + } + + public String name() { + return name; + } +} diff --git a/net/loveruby/cflat/type/UnsignedCharRef.java b/net/loveruby/cflat/type/UnsignedCharRef.java new file mode 100644 index 0000000..53e6ce1 --- /dev/null +++ b/net/loveruby/cflat/type/UnsignedCharRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class UnsignedCharRef extends TypeRef { + public UnsignedCharRef() { + } + + public boolean isUnsignedChar() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof UnsignedCharRef); + } + + public int hashCode() { + return 4; + } +} diff --git a/net/loveruby/cflat/type/UnsignedCharType.java b/net/loveruby/cflat/type/UnsignedCharType.java new file mode 100644 index 0000000..e2ff2ef --- /dev/null +++ b/net/loveruby/cflat/type/UnsignedCharType.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.type; + +public class UnsignedCharType extends IntegerType { + public UnsignedCharType(int size) { + super(size, false, "uchar"); + } +} diff --git a/net/loveruby/cflat/type/UnsignedIntRef.java b/net/loveruby/cflat/type/UnsignedIntRef.java new file mode 100644 index 0000000..dd722dd --- /dev/null +++ b/net/loveruby/cflat/type/UnsignedIntRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class UnsignedIntRef extends TypeRef { + public UnsignedIntRef() { + } + + public boolean isUnsignedInt() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof UnsignedIntRef); + } + + public int hashCode() { + return 6; + } +} diff --git a/net/loveruby/cflat/type/UnsignedIntType.java b/net/loveruby/cflat/type/UnsignedIntType.java new file mode 100644 index 0000000..5b31ad6 --- /dev/null +++ b/net/loveruby/cflat/type/UnsignedIntType.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.type; + +public class UnsignedIntType extends IntegerType { + public UnsignedIntType(int size) { + super(size, false, "uint"); + } +} diff --git a/net/loveruby/cflat/type/UnsignedLongLongRef.java b/net/loveruby/cflat/type/UnsignedLongLongRef.java new file mode 100644 index 0000000..30b3498 --- /dev/null +++ b/net/loveruby/cflat/type/UnsignedLongLongRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class UnsignedLongLongRef extends TypeRef { + public UnsignedLongLongRef() { + } + + public boolean isUnsignedLongLong() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof UnsignedLongLongRef); + } + + public int hashCode() { + return -3; + } +} diff --git a/net/loveruby/cflat/type/UnsignedLongLongType.java b/net/loveruby/cflat/type/UnsignedLongLongType.java new file mode 100644 index 0000000..31b6f32 --- /dev/null +++ b/net/loveruby/cflat/type/UnsignedLongLongType.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.type; + +public class UnsignedLongLongType extends IntegerType { + public UnsignedLongLongType(int size) { + super(size, false, "ulong_long"); + } +} diff --git a/net/loveruby/cflat/type/UnsignedLongRef.java b/net/loveruby/cflat/type/UnsignedLongRef.java new file mode 100644 index 0000000..2a0dc59 --- /dev/null +++ b/net/loveruby/cflat/type/UnsignedLongRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class UnsignedLongRef extends TypeRef { + public UnsignedLongRef() { + } + + public boolean isUnsignedLong() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof UnsignedLongRef); + } + + public int hashCode() { + return 7; + } +} diff --git a/net/loveruby/cflat/type/UnsignedLongType.java b/net/loveruby/cflat/type/UnsignedLongType.java new file mode 100644 index 0000000..444ca7a --- /dev/null +++ b/net/loveruby/cflat/type/UnsignedLongType.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.type; + +public class UnsignedLongType extends IntegerType { + public UnsignedLongType(int size) { + super(size, false, "ulong"); + } +} diff --git a/net/loveruby/cflat/type/UnsignedShortRef.java b/net/loveruby/cflat/type/UnsignedShortRef.java new file mode 100644 index 0000000..d5cbd14 --- /dev/null +++ b/net/loveruby/cflat/type/UnsignedShortRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class UnsignedShortRef extends TypeRef { + public UnsignedShortRef() { + } + + public boolean isUnsignedShort() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof UnsignedShortRef); + } + + public int hashCode() { + return 5; + } +} diff --git a/net/loveruby/cflat/type/UnsignedShortType.java b/net/loveruby/cflat/type/UnsignedShortType.java new file mode 100644 index 0000000..0ee1951 --- /dev/null +++ b/net/loveruby/cflat/type/UnsignedShortType.java @@ -0,0 +1,7 @@ +package net.loveruby.cflat.type; + +public class UnsignedShortType extends IntegerType { + public UnsignedShortType(int size) { + super(size, false, "ushort"); + } +} diff --git a/net/loveruby/cflat/type/UserType.java b/net/loveruby/cflat/type/UserType.java new file mode 100644 index 0000000..b921569 --- /dev/null +++ b/net/loveruby/cflat/type/UserType.java @@ -0,0 +1,41 @@ +package net.loveruby.cflat.type; +import net.loveruby.cflat.ast.TypeNode; + +public class UserType extends Type { + protected String name; + protected TypeNode real; + + public UserType(String n, TypeNode t) { + name = n; + real = t; + } + + public String name() { + return name; + } + + public Type real() { + return real.type(); + } + + public TypeNode typeNode() { + return real; + } + + public String textize() { + return name; + } + + public long alignment() { return real().alignment(); } + public long size() { return real().size(); } + public boolean isReferable() { return real().isReferable(); } + public boolean isInt() { return real().isInt(); } + public boolean isInteger() { return real().isInteger(); } + public boolean isNumeric() { return real().isNumeric(); } + public boolean isPointer() { return real().isPointer(); } + public boolean isArray() { return real().isArray(); } + public boolean isStruct() { return real().isStruct(); } + public boolean isUnion() { return real().isUnion(); } + public boolean isUserType() { return true; } + public boolean isFunction() { return real().isFunction(); } +} diff --git a/net/loveruby/cflat/type/UserTypeRef.java b/net/loveruby/cflat/type/UserTypeRef.java new file mode 100644 index 0000000..3e3abd4 --- /dev/null +++ b/net/loveruby/cflat/type/UserTypeRef.java @@ -0,0 +1,26 @@ +package net.loveruby.cflat.type; + +public class UserTypeRef extends TypeRef { + protected String name; + + public UserTypeRef(String n) { + name = n; + } + + public boolean isUserType() { + return true; + } + + public String name() { + return name; + } + + public boolean equals(Object other) { + if (!(other instanceof UserTypeRef)) return false; + return name.equals(((UserTypeRef)other).name); + } + + public int hashCode() { + return (1 << 12) & name.hashCode(); + } +} diff --git a/net/loveruby/cflat/type/VoidType.java b/net/loveruby/cflat/type/VoidType.java new file mode 100644 index 0000000..0979528 --- /dev/null +++ b/net/loveruby/cflat/type/VoidType.java @@ -0,0 +1,20 @@ +package net.loveruby.cflat.type; + +public class VoidType extends Type { + public VoidType() { + } + + public boolean isVoid() { + return true; + } + + public long size() { + // FIXME???: use exception + // This error is caused by user error?? + throw new Error("VoidType#size called"); + } + + public String textize() { + return "void"; + } +} diff --git a/net/loveruby/cflat/type/VoidTypeRef.java b/net/loveruby/cflat/type/VoidTypeRef.java new file mode 100644 index 0000000..8718254 --- /dev/null +++ b/net/loveruby/cflat/type/VoidTypeRef.java @@ -0,0 +1,18 @@ +package net.loveruby.cflat.type; + +public class VoidTypeRef extends TypeRef { + public VoidTypeRef() { + } + + public boolean isVoidTypeRef() { + return true; + } + + public boolean equals(Object other) { + return (other instanceof VoidTypeRef); + } + + public int hashCode() { + return -1; + } +} diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..c95a8d8 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,47 @@ +CC = gcc +CFLAGS = -Wall -O -fno-omit-frame-pointer +CBC = ./cbc +CBPROGS = zero one hello hello2 hello3 hello4 integer string \ + funcall0 funcall1 funcall2 funcall3 funcall4 funcall5 \ + param lvar1 lvar2 comm scomm gvar sgvar slvar slcomm \ + add sub mul div mod bitand bitor bitxor bitnot lshift rshift \ + logicalnot unaryplus unaryminus \ + eq neq gt lt gteq lteq \ + assign opassign inc dec \ + if1 if2 condexpr logicaland logicalor \ + while1 while2 while3 while-break while-continue \ + dowhile1 dowhile2 dowhile3 dowhile-break dowhile-continue \ + for1 for-break for-continue \ + array struct struct-semcheck union union-semcheck \ + pointer ptrmemb funcptr \ + charops shortops intops longops \ + ucharops ushortops uintops ulongops \ + block cast defvar mbc \ + +# immscope cast + +.SUFFIXES: +.SUFFIXES: .cb . +.cb: + $(CBC) $< + +default: cbprograms + +test: cbprograms + ./test.sh + +cbprograms: $(CBPROGS) + +errors: + -$(CBC) struct-semcheck2.cb + -$(CBC) struct-semcheck3.cb + -$(CBC) struct-semcheck4.cb + -$(CBC) union-semcheck2.cb + -$(CBC) union-semcheck3.cb + -$(CBC) union-semcheck4.cb + -$(CBC) break-semcheck.cb + -$(CBC) continue-semcheck.cb + -$(CBC) funcall-semcheck.cb + +clean: + rm -f $(CBPROGS) *.s *.o diff --git a/test/add.cb b/test/add.cb new file mode 100644 index 0000000..e2fd403 --- /dev/null +++ b/test/add.cb @@ -0,0 +1,36 @@ +import stdio; + +static int g = 3; +static int c; + +int +main(int argc, char **argv) +{ + int i; + int j = 0; + + printf("%d", 1 + 0); + printf(";%d", 2 + j); + i = 2; + j = 1; + printf(";%d", i + j); + printf(";%d", j + g); + printf(";%d", i + g); + printf(";%d", f(5)); // 6 + printf(";%d", f(5) + 1); + printf(";%d", f(5) + i); // 8 + c = 5; + printf(";%d", f(3) + c); + i = 9; + printf(";%d", f(i)); + j = 1; + printf(";%d", f(i) + j); + puts(""); + return 0; +} + +int +f(int i) +{ + return i + 1; +} diff --git a/test/array.cb b/test/array.cb new file mode 100644 index 0000000..665a0c4 --- /dev/null +++ b/test/array.cb @@ -0,0 +1,18 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int[5] a; + + a[0] = 1; + a[1] = 3; + a[2] = 5; + a[3] = 7; + a[4] = 9; + printf("%d;%d;%d\n", a[0], a[2], a[4]); + //printf("%d\n", a[0]); + //printf("%d\n", a[2]); + //printf("%d\n", a[4]); + return 0; +} diff --git a/test/assign.cb b/test/assign.cb new file mode 100644 index 0000000..10cbdb7 --- /dev/null +++ b/test/assign.cb @@ -0,0 +1,11 @@ +import stdio; + +int main(void) { + int x, y; + + x = 1; + y = 1; + x = y = 2; + printf("%d;%d\n", x, y); + return 0; +} diff --git a/test/bitand.cb b/test/bitand.cb new file mode 100644 index 0000000..ad21355 --- /dev/null +++ b/test/bitand.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d;%d;%d", 7 & 0, 7 & 1, 7 & 2, 7 & 3, 7 & 4); + puts(""); + return 0; +} diff --git a/test/bitnot.cb b/test/bitnot.cb new file mode 100644 index 0000000..151328c --- /dev/null +++ b/test/bitnot.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d", ~0, ~1, ~(-1)); + puts(""); + return 0; +} diff --git a/test/bitor.cb b/test/bitor.cb new file mode 100644 index 0000000..3255f82 --- /dev/null +++ b/test/bitor.cb @@ -0,0 +1,11 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d;%d;%d;%d", 0|0, 0|1, 0|2, 1|2, 2|2, 2|4); + printf(";%d", (0 | 2) * 4); + printf(";%d", 5 * (0 | 2)); + puts(""); + return 0; +} diff --git a/test/bitxor.cb b/test/bitxor.cb new file mode 100644 index 0000000..af4bbb2 --- /dev/null +++ b/test/bitxor.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d;%d;%d", 0 ^ 1, 0 ^ 2, 1 ^ 1, 2 ^ 2, 3 ^ 1); + puts(""); + return 0; +} diff --git a/test/block.cb b/test/block.cb new file mode 100644 index 0000000..c33a5b0 --- /dev/null +++ b/test/block.cb @@ -0,0 +1,13 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 1; + + { + int i = 2; + printf("%d\n", 2); + } + return 0; +} diff --git a/test/break-semcheck.cb b/test/break-semcheck.cb new file mode 100644 index 0000000..0f2a270 --- /dev/null +++ b/test/break-semcheck.cb @@ -0,0 +1,5 @@ +int +main(int argc, char **argv) { + break; + return 0; +} diff --git a/test/cast.cb b/test/cast.cb new file mode 100644 index 0000000..3e6d962 --- /dev/null +++ b/test/cast.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + short n = 5000; + printf("%ld\n", (long)((long)n * (long)n)); + return 0; +} diff --git a/test/cbc b/test/cbc new file mode 100755 index 0000000..60c7a10 --- /dev/null +++ b/test/cbc @@ -0,0 +1,2 @@ +#!/bin/sh +java -classpath ../build/classes net.loveruby.cflat.compiler.Compiler ${@+"$@"} diff --git a/test/charops.cb b/test/charops.cb new file mode 100644 index 0000000..4f3a890 --- /dev/null +++ b/test/charops.cb @@ -0,0 +1,18 @@ +import stdio; + +int +main(int argc, char **argv) +{ + char i = 1; + + i <<= 1; + printf("%hhd", i); + i <<= 5; + printf(";%hhd", i); + i <<= 1; + printf(";%hhd", i); + i <<= 1; + printf(";%hhd", i); + puts(""); + return 0; +} diff --git a/test/comm.cb b/test/comm.cb new file mode 100644 index 0000000..96bd0f9 --- /dev/null +++ b/test/comm.cb @@ -0,0 +1,13 @@ +import stdio; + +int i; + +int +main(int argc, char **argv) +{ + i = 1; + printf("%d", i); + i = 2; + printf(";%d\n", i); + return 0; +} diff --git a/test/condexpr.cb b/test/condexpr.cb new file mode 100644 index 0000000..2d64ac3 --- /dev/null +++ b/test/condexpr.cb @@ -0,0 +1,12 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%s", 1 ? "OK" : "NG"); + printf(";%s", 0 ? "NG" : "OK"); + printf(";%s", 0==0 ? "OK" : "NG"); + printf(";%s", 0==1 ? "NG" : "OK"); + puts(""); + return 0; +} diff --git a/test/continue-semcheck.cb b/test/continue-semcheck.cb new file mode 100644 index 0000000..7991f37 --- /dev/null +++ b/test/continue-semcheck.cb @@ -0,0 +1,5 @@ +int +main(int argc, char **argv) { + continue; + return 0; +} diff --git a/test/dec.cb b/test/dec.cb new file mode 100644 index 0000000..dac964d --- /dev/null +++ b/test/dec.cb @@ -0,0 +1,23 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 4; + int j; + + printf("%d", i); // 4 + --i; + printf(";%d", i); // 3 + j = --i; + printf(";%d", j); // 2 + printf(";%d", i); // 2 + i--; + printf(";%d", i); // 1 + j = i--; + printf(";%d", j); // 1 + printf(";%d", i); // 0 + puts(""); + + return 0; +} diff --git a/test/defun-semcheck.cb b/test/defun-semcheck.cb new file mode 100644 index 0000000..2310b08 --- /dev/null +++ b/test/defun-semcheck.cb @@ -0,0 +1 @@ +void f(int a, int a) {} diff --git a/test/defvar.cb b/test/defvar.cb new file mode 100644 index 0000000..177168c --- /dev/null +++ b/test/defvar.cb @@ -0,0 +1,10 @@ +import stdio; + +int main(void) +{ + int x = 7, y = 2, z; + z = 3; + x = 1; + printf("%d;%d;%d\n", x, y, z); + return 0; +} diff --git a/test/div.cb b/test/div.cb new file mode 100644 index 0000000..e7f205d --- /dev/null +++ b/test/div.cb @@ -0,0 +1,8 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d;%d\n", 1 / 1, 2 / 1, 4 / 2, 5 / 2); + return 0; +} diff --git a/test/dowhile-break.cb b/test/dowhile-break.cb new file mode 100644 index 0000000..913fa7b --- /dev/null +++ b/test/dowhile-break.cb @@ -0,0 +1,12 @@ +import stdio; + +int +main(int argc, char **argv) +{ + do { + break; + puts("NG"); + } while (1); + puts("OK"); + return 0; +} diff --git a/test/dowhile-continue.cb b/test/dowhile-continue.cb new file mode 100644 index 0000000..e7acbde --- /dev/null +++ b/test/dowhile-continue.cb @@ -0,0 +1,15 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 3; + + do { + i--; + continue; + puts("NG"); + } while (i); + puts("OK"); + return 0; +} diff --git a/test/dowhile1.cb b/test/dowhile1.cb new file mode 100644 index 0000000..03fcdb2 --- /dev/null +++ b/test/dowhile1.cb @@ -0,0 +1,11 @@ +import stdio; + +int +main(int argc, char **argv) +{ + do { + puts("OK"); + } + while (0); + return 0; +} diff --git a/test/dowhile2.cb b/test/dowhile2.cb new file mode 100644 index 0000000..175fcb7 --- /dev/null +++ b/test/dowhile2.cb @@ -0,0 +1,13 @@ +import stdio; + +int +main(int argc, char **argv) +{ + do { + puts("OK"); + return 0; + } + while (1); + puts("NG"); + return 1; +} diff --git a/test/dowhile3.cb b/test/dowhile3.cb new file mode 100644 index 0000000..736db4d --- /dev/null +++ b/test/dowhile3.cb @@ -0,0 +1,15 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 3; + + printf("%d", i); + do { + printf(";%d", i); + i--; + } while (i); + printf(";%d\n", i); + return 0; +} diff --git a/test/eq.cb b/test/eq.cb new file mode 100644 index 0000000..d5194c5 --- /dev/null +++ b/test/eq.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d", (5 == 3), (5 == 5), (3 == 5)); + puts(""); + return 0; +} diff --git a/test/for-break.cb b/test/for-break.cb new file mode 100644 index 0000000..aa2a952 --- /dev/null +++ b/test/for-break.cb @@ -0,0 +1,15 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i; + + for (i = 1; i; i--) { + break; + puts("NG"); + } + puts("OK"); + + return 0; +} diff --git a/test/for-continue.cb b/test/for-continue.cb new file mode 100644 index 0000000..3e3e4bb --- /dev/null +++ b/test/for-continue.cb @@ -0,0 +1,15 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i; + + for (i = 3; i; i--) { + continue; + puts("NG"); + } + puts("OK"); + + return 0; +} diff --git a/test/for1.cb b/test/for1.cb new file mode 100644 index 0000000..313a81e --- /dev/null +++ b/test/for1.cb @@ -0,0 +1,14 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 3; + + printf("%d", i); + for (i = 3; i; i--) { + printf(";%d", i); + } + printf(";%d\n", i); + return 0; +} diff --git a/test/funcall-semcheck.cb b/test/funcall-semcheck.cb new file mode 100644 index 0000000..53255e5 --- /dev/null +++ b/test/funcall-semcheck.cb @@ -0,0 +1,6 @@ +int +main(int argc, char **argv) +{ + f(); + return 0; +} diff --git a/test/funcall0.cb b/test/funcall0.cb new file mode 100644 index 0000000..546f498 --- /dev/null +++ b/test/funcall0.cb @@ -0,0 +1,11 @@ +int +main(int argc, char **argv) +{ + return f(); +} + +int +f(void) +{ + return 0; +} diff --git a/test/funcall1.cb b/test/funcall1.cb new file mode 100644 index 0000000..af7c6de --- /dev/null +++ b/test/funcall1.cb @@ -0,0 +1,11 @@ +int +main(int argc, char **argv) +{ + return f(0); +} + +int +f(int i) +{ + return i; +} diff --git a/test/funcall2.cb b/test/funcall2.cb new file mode 100644 index 0000000..2834e9d --- /dev/null +++ b/test/funcall2.cb @@ -0,0 +1,11 @@ +int +main(int argc, char **argv) +{ + return f(999, 0); +} + +int +f(int i, int j) +{ + return j; +} diff --git a/test/funcall3.cb b/test/funcall3.cb new file mode 100644 index 0000000..698ea43 --- /dev/null +++ b/test/funcall3.cb @@ -0,0 +1,11 @@ +int +main(int argc, char **argv) +{ + return f(998, 999, 0); +} + +int +f(int i, int j, int k) +{ + return k; +} diff --git a/test/funcall4.cb b/test/funcall4.cb new file mode 100644 index 0000000..3af92a3 --- /dev/null +++ b/test/funcall4.cb @@ -0,0 +1,7 @@ +int f(int i, int j) { return j; } + +int +main(int argc, char **argv) +{ + return f(2, 1) - 1; +} diff --git a/test/funcall5.cb b/test/funcall5.cb new file mode 100644 index 0000000..64d7e88 --- /dev/null +++ b/test/funcall5.cb @@ -0,0 +1,28 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d", + 1); + printf(";%d;%d", + 2, 3); + printf(";%d;%d;%d", + 4, 5, 6); + printf(";%d;%d;%d;%d", + 7, 8, 9, 10); // 4 + printf(";%d;%d;%d;%d;%d", + 11, 12, 13, 14, 15); + printf(";%d;%d;%d;%d;%d;%d", + 16, 17, 18, 19, 20, 21); + printf(";%d;%d;%d;%d;%d;%d;%d", + 22, 23, 24, 25, 26, 27, 28); + printf(";%d;%d;%d;%d;%d;%d;%d;%d", + 29, 30, 31, 32, 33, 34, 35, 36); + printf(";%d;%d;%d;%d;%d;%d;%d;%d;%d", + 37, 38, 39, 40, 41, 42, 43, 44, 45); + printf(";%d;%d;%d;%d;%d;%d;%d;%d;%d;%d", + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55); + puts(""); + return 0; +} diff --git a/test/funcptr.cb b/test/funcptr.cb new file mode 100644 index 0000000..af5624d --- /dev/null +++ b/test/funcptr.cb @@ -0,0 +1,11 @@ +import stdio; + +int +main(int argc, char **argv) +{ + void (*)(char*) f; + + f = puts; + f("OK"); + return 0; +} diff --git a/test/gt.cb b/test/gt.cb new file mode 100644 index 0000000..b50372f --- /dev/null +++ b/test/gt.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d", (5 > 3), (5 > 5), (3 > 5)); + puts(""); + return 0; +} diff --git a/test/gteq.cb b/test/gteq.cb new file mode 100644 index 0000000..070652f --- /dev/null +++ b/test/gteq.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d", (5 >= 3), (5 >= 5), (3 >= 5)); + puts(""); + return 0; +} diff --git a/test/gvar.cb b/test/gvar.cb new file mode 100644 index 0000000..02bcb2a --- /dev/null +++ b/test/gvar.cb @@ -0,0 +1,12 @@ +import stdio; + +int i = 1; + +int +main(int argc, char **argv) +{ + printf("%d", i); + i = 2; + printf(";%d\n", i); + return 0; +} diff --git a/test/hello.cb b/test/hello.cb new file mode 100644 index 0000000..14f1d6c --- /dev/null +++ b/test/hello.cb @@ -0,0 +1,8 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("Hello, World!\n"); + return 0; +} diff --git a/test/hello2.cb b/test/hello2.cb new file mode 100644 index 0000000..b8480e3 --- /dev/null +++ b/test/hello2.cb @@ -0,0 +1,8 @@ +import stdio; + +int +main(int argc, char **argv) +{ + puts("Hello, World!"); + return 0; +} diff --git a/test/hello3.cb b/test/hello3.cb new file mode 100644 index 0000000..bd6dd58 --- /dev/null +++ b/test/hello3.cb @@ -0,0 +1,8 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%s\n", "Hello, World!"); + return 0; +} diff --git a/test/hello4.cb b/test/hello4.cb new file mode 100644 index 0000000..5fbfb52 --- /dev/null +++ b/test/hello4.cb @@ -0,0 +1,10 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("Hell"); + printf("o, Wor"); + printf("ld!\n"); + return 0; +} diff --git a/test/if1.cb b/test/if1.cb new file mode 100644 index 0000000..8d30a38 --- /dev/null +++ b/test/if1.cb @@ -0,0 +1,13 @@ +import stdio; + +int +main(int argc, char **argv) +{ + if (2) { + puts("OK"); + } + else { + puts("NG"); + } + return 0; +} diff --git a/test/if2.cb b/test/if2.cb new file mode 100644 index 0000000..7419548 --- /dev/null +++ b/test/if2.cb @@ -0,0 +1,8 @@ +import stdio; + +int +main(int argc, char **argv) +{ + if (2) { puts("OK"); } + return 0; +} diff --git a/test/inc.cb b/test/inc.cb new file mode 100644 index 0000000..a149065 --- /dev/null +++ b/test/inc.cb @@ -0,0 +1,23 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 0; + int j; + + printf("%d", i); // 0 + ++i; + printf(";%d", i); // 1 + j = ++i; + printf(";%d", j); // 2 + printf(";%d", i); // 2 + i++; + printf(";%d", i); // 3 + j = i++; + printf(";%d", j); // 3 + printf(";%d", i); // 4 + puts(""); + + return 0; +} diff --git a/test/integer.cb b/test/integer.cb new file mode 100644 index 0000000..0a39ed3 --- /dev/null +++ b/test/integer.cb @@ -0,0 +1,12 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d", 0, 00, 0x0); + printf(";%d;%d;%d", 1, 01, 0x1); + printf(";%d;%d;%d", 9, 011, 0x9); + printf(";%d;%d;%d", 17, 021, 0x11); + puts(""); + return 0; +} diff --git a/test/intops.cb b/test/intops.cb new file mode 100644 index 0000000..6acc472 --- /dev/null +++ b/test/intops.cb @@ -0,0 +1,18 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 1; + + i <<= 1; + printf("%d", i); + i <<= 29; + printf(";%d", i); + i <<= 1; + printf(";%d", i); + i <<= 1; + printf(";%d", i); + puts(""); + return 0; +} diff --git a/test/logicaland.cb b/test/logicaland.cb new file mode 100644 index 0000000..6babe7b --- /dev/null +++ b/test/logicaland.cb @@ -0,0 +1,8 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d;%d\n", 0&&0, 1&&0, 0&&1, 1&&2); + return 0; +} diff --git a/test/logicalnot.cb b/test/logicalnot.cb new file mode 100644 index 0000000..3d27e7b --- /dev/null +++ b/test/logicalnot.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d", !0, !1, !2); + puts(""); + return 0; +} diff --git a/test/logicalor.cb b/test/logicalor.cb new file mode 100644 index 0000000..4d7dd6a --- /dev/null +++ b/test/logicalor.cb @@ -0,0 +1,8 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d;%d\n", 0||0, 1||0, 0||1, 1||2); + return 0; +} diff --git a/test/longops.cb b/test/longops.cb new file mode 100644 index 0000000..021ee67 --- /dev/null +++ b/test/longops.cb @@ -0,0 +1,19 @@ +import stdio; + +int +main(int argc, char **argv) +{ + long i = 1; + + printf("%ld", i); + i <<= 1; + printf(";%ld", i); + i <<= 61; + printf(";%ld", i); + i <<= 1; + printf(";%ld", i); + i <<= 1; + printf(";%ld", i); + puts(""); + return 0; +} diff --git a/test/lshift.cb b/test/lshift.cb new file mode 100644 index 0000000..264cdf9 --- /dev/null +++ b/test/lshift.cb @@ -0,0 +1,10 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 1; + printf("%d;%d;%d;%d;%d", i << 0, i << 1, i << 2, i << 3, i << 4); + puts(""); + return 0; +} diff --git a/test/lt.cb b/test/lt.cb new file mode 100644 index 0000000..f29edfd --- /dev/null +++ b/test/lt.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d", (5 < 3), (5 < 5), (3 < 5)); + puts(""); + return 0; +} diff --git a/test/lteq.cb b/test/lteq.cb new file mode 100644 index 0000000..7b72b6e --- /dev/null +++ b/test/lteq.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d", (5 <= 3), (5 <= 5), (3 <= 5)); + puts(""); + return 0; +} diff --git a/test/lvar1.cb b/test/lvar1.cb new file mode 100644 index 0000000..af10ebc --- /dev/null +++ b/test/lvar1.cb @@ -0,0 +1,11 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i; + + i = 1; printf("%d", i); + i = 2; printf(";%d\n", i); + return 0; +} diff --git a/test/lvar2.cb b/test/lvar2.cb new file mode 100644 index 0000000..42864d1 --- /dev/null +++ b/test/lvar2.cb @@ -0,0 +1,20 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i; + int j = 3; + + i = 1; + printf("%d", i); + i = 2; + printf(";%d", i); + printf(";%d", j); + j = 4; + printf(";%d", j); + i = 5; + printf(";%d", i); + puts(""); + return 0; +} diff --git a/test/mbc.cb b/test/mbc.cb new file mode 100644 index 0000000..5ace77f --- /dev/null +++ b/test/mbc.cb @@ -0,0 +1,8 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("マルチバイト文字ですよ〜\n"); + return 0; +} diff --git a/test/mod.cb b/test/mod.cb new file mode 100644 index 0000000..8349549 --- /dev/null +++ b/test/mod.cb @@ -0,0 +1,8 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d;%d;%d\n", 1 % 1, 2 % 2, 3 % 2, 14 % 5, 7 % 8); + return 0; +} diff --git a/test/mul.cb b/test/mul.cb new file mode 100644 index 0000000..9845448 --- /dev/null +++ b/test/mul.cb @@ -0,0 +1,8 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d\n", 1 * 1, 2 * 2, 3 * 5); + return 0; +} diff --git a/test/neq.cb b/test/neq.cb new file mode 100644 index 0000000..20532ba --- /dev/null +++ b/test/neq.cb @@ -0,0 +1,9 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf("%d;%d;%d", (5 != 3), (5 != 5), (3 != 5)); + puts(""); + return 0; +} diff --git a/test/one.cb b/test/one.cb new file mode 100644 index 0000000..ed5f8b8 --- /dev/null +++ b/test/one.cb @@ -0,0 +1,5 @@ +int +main(int argc, char **argv) +{ + return 1; +} diff --git a/test/opassign.cb b/test/opassign.cb new file mode 100644 index 0000000..631da00 --- /dev/null +++ b/test/opassign.cb @@ -0,0 +1,32 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 3; + + printf("%d", i); // 3 + i += 1; + printf(";%d", i); // 4 + i -= 1; + printf(";%d", i); // 3 + i *= 4; + printf(";%d", i); // 12 + i /= 3; + printf(";%d", i); // 4 + i %= 3; + printf(";%d", i); // 1 + i &= 7; + printf(";%d", i); // 1 + i |= 6; + printf(";%d", i); // 7 + i ^= 2; + printf(";%d", i); // 5 + i >>= 2; + printf(";%d", i); // 1 + i <<= 2; + printf(";%d", i); // 4 + puts(""); + + return 0; +} diff --git a/test/param.cb b/test/param.cb new file mode 100644 index 0000000..a92597f --- /dev/null +++ b/test/param.cb @@ -0,0 +1,16 @@ +import stdio; + +int +main(int argc, char **argv) +{ + return f(1); +} + +int +f(int i) +{ + printf("%d", i); + i = 2; + printf(";%d\n", i); + return 0; +} diff --git a/test/pointer.cb b/test/pointer.cb new file mode 100644 index 0000000..866f0d2 --- /dev/null +++ b/test/pointer.cb @@ -0,0 +1,13 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i; + int *ptr; + + ptr = &i; + *ptr = 5; + printf("%d;%d\n", i, *ptr); + return 0; +} diff --git a/test/ptrmemb.cb b/test/ptrmemb.cb new file mode 100644 index 0000000..354d533 --- /dev/null +++ b/test/ptrmemb.cb @@ -0,0 +1,19 @@ +import stdio; + +struct a { + int x; + int y; +}; + +int +main(int argc, char **argv) +{ + struct a a; + struct a* ptr; + + ptr = &a; + ptr->x = 1; + ptr->y = 2; + printf("%d;%d\n", ptr->x, ptr->y); + return 0; +} diff --git a/test/rshift.cb b/test/rshift.cb new file mode 100644 index 0000000..1a2a0bd --- /dev/null +++ b/test/rshift.cb @@ -0,0 +1,11 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 16; + + printf("%d;%d;%d;%d;%d", i >> 0, i >> 1, i >> 2, i >> 3, i >> 4); + puts(""); + return 0; +} diff --git a/test/scomm.cb b/test/scomm.cb new file mode 100644 index 0000000..ae33c47 --- /dev/null +++ b/test/scomm.cb @@ -0,0 +1,13 @@ +import stdio; + +static int static_common_symbol; + +int +main(int argc, char **argv) +{ + static_common_symbol = 1; + printf("%d", static_common_symbol); + static_common_symbol = 2; + printf(";%d\n", static_common_symbol); + return 0; +} diff --git a/test/sgvar.cb b/test/sgvar.cb new file mode 100644 index 0000000..70a2533 --- /dev/null +++ b/test/sgvar.cb @@ -0,0 +1,12 @@ +import stdio; + +static int static_global_variable = 1; + +int +main(int argc, char **argv) +{ + printf("%d", static_global_variable); + static_global_variable = 2; + printf(";%d\n", static_global_variable); + return 0; +} diff --git a/test/shortops.cb b/test/shortops.cb new file mode 100644 index 0000000..bb28d9a --- /dev/null +++ b/test/shortops.cb @@ -0,0 +1,18 @@ +import stdio; + +int +main(int argc, char **argv) +{ + short i = 1; + + i <<= 1; + printf("%hd", i); + i <<= (short)13; + printf(";%hd", i); + i <<= 1; + printf(";%hd", i); + i <<= 1; + printf(";%hd", i); + puts(""); + return 0; +} diff --git a/test/shunit.sh b/test/shunit.sh new file mode 100644 index 0000000..99816a1 --- /dev/null +++ b/test/shunit.sh @@ -0,0 +1,195 @@ +# +# $Id: shunit.sh 1096 2006-11-02 12:31:46Z aamine $ +# +# Simple Unit Test Framework for Shell Scripts +# + +n_tests=0 +n_failed=0 +test_finished() { + rm -rf tc.* + echo + if [ "$n_failed" = "0" ] + then + echo "PASS ($n_tests tests) -- `hostname` / `uname -srm`" + exit 0 + else + echo "FAIL ($n_failed/$n_tests failed) -- `hostname` / `uname -srm`" + exit 1 + fi +} + +print() { + if [ `/bin/echo -n x` = "-n" ] + then + /bin/echo $1'\c' + else + /bin/echo -n $1 + fi +} + +progress() { + print '.' +} + +begin_test() { + progress + n_tests=`expr $n_tests "+" 1` +} + +test_failed() { + n_failed=`expr $n_failed "+" 1` +} + +assert_status() { + begin_test + expected=$1; shift + mycmd=$1; shift + eval "$mycmd" >/dev/null 2>&1 + really=$? + assert_not_coredump || return + if [ "$really" != "$expected" ] + then + echo "shunit[$mycmd]: status $expected expected but was: $really" + test_failed + return 1 + fi + return 0 +} + +assert_error() { + begin_test + mycmd=$1; shift + eval "$mycmd" >/dev/null 2>&1 + really=$? + assert_not_coredump || return + if [ "$really" = "0" ] + then + echo "shunit[$mycmd]: non-zero status expected but was: $really" + test_failed + return 1 + fi + return 0 +} + +assert_eq() { + begin_test + expected="$1"; shift + really="$1"; shift + if [ "$really" != "$expected" ] + then + echo "shunit: <$expected> expected but is: <$really>" + test_failed + return 1 + fi + return 0 +} + +assert_equal() { + begin_test + _f="no" + excmd=$1; shift + mycmd=$1; shift + eval "$excmd" >tc.out.expected 2>tc.err.expected + eval "$mycmd" >tc.out.real 2>tc.err.real + assert_not_coredump || return + cmp tc.out.real tc.out.expected >/dev/null 2>&1 + if [ "$?" != "0" ] + then + echo "stdout differ: \"$excmd\" and \"$mycmd\"" + diff -u tc.out.expected tc.out.real + echo "----" + _f="yes" + fi + cmp tc.err.real tc.err.expected >/dev/null 2>&1 + if [ "$?" != "0" ] + then + echo "stderr differ: \"$excmd\" and \"$mycmd\"" + diff -u tc.err.expected tc.err.real + echo "----" + _f="yes" + fi + if [ "$_f" = "yes" ] + then + test_failed + return 1 + fi + return 0 +} + +assert_equal_stdout() { + begin_test + _f="no" + excmd=$1; shift + mycmd=$1; shift + eval "$excmd" >tc.out.expected 2>/dev/null + eval "$mycmd" >tc.out.real 2>/dev/null + assert_not_coredump || return + cmp tc.out.real tc.out.expected >/dev/null 2>&1 + if [ "$?" != "0" ] + then + echo "stdout differ: \"$excmd\" and \"$mycmd\"" + diff -u tc.out.expected tc.out.real + echo "----" + test_failed + fi + return 0 +} + +assert_stdout() { + begin_test + expected=$1; shift + mycmd=$1; shift + echo "$expected" > tc.out.expected + eval "$mycmd" >tc.out.real 2>/dev/null + assert_not_coredump || return + cmp tc.out.expected tc.out.real >/dev/null 2>&1 + if [ "$?" != "0" ] + then + echo "stdout differ: string \"$expected\" and cmd \"$mycmd\"" + diff -u tc.out.expected tc.out.real + echo "----" + test_failed + fi + return 0 +} + +rm -f core +assert_not_coredump() { + begin_test + if [ -f core ] + then + echo "core dumped: $mycmd" + echo "----" + test_failed + return 1 + fi + rm -f core + return 0 +} + +assert_not_exist() { + begin_test + file=$1; shift + if [ -f $file ] + then + echo "exists: $file" + echo "----" + test_failed + return 1 + fi + return 0 +} + +assert_directory() { + begin_test + dir=$1; shift + if [ ! -d $dir ] + then + echo "not directory: $dir" + echo "----" + test_failed + return 1 + fi + return 0 +} diff --git a/test/slcomm.cb b/test/slcomm.cb new file mode 100644 index 0000000..59f444f --- /dev/null +++ b/test/slcomm.cb @@ -0,0 +1,14 @@ +import stdio; + +int +main(int argc, char **argv) +{ + static int static_variable; + + static_variable = 1; + printf("%d", static_variable); + static_variable = 2; + printf(";%d", static_variable); + puts(""); + return 0; +} diff --git a/test/slvar.cb b/test/slvar.cb new file mode 100644 index 0000000..70baad9 --- /dev/null +++ b/test/slvar.cb @@ -0,0 +1,13 @@ +import stdio; + +int +main(int argc, char **argv) +{ + static int static_variable = 1; + + printf("%d", static_variable); + static_variable = 2; + printf(";%d", static_variable); + puts(""); + return 0; +} diff --git a/test/stdio.hb b/test/stdio.hb new file mode 100644 index 0000000..9e0e24a --- /dev/null +++ b/test/stdio.hb @@ -0,0 +1,4 @@ +extern void printf(char *fmt, ...); +extern void puts(char *str); +extern void putc(int c); +extern int getc(void); diff --git a/test/stdlib.hb b/test/stdlib.hb new file mode 100644 index 0000000..d51f045 --- /dev/null +++ b/test/stdlib.hb @@ -0,0 +1 @@ +void exit(int status); diff --git a/test/string.cb b/test/string.cb new file mode 100644 index 0000000..cdd7681 --- /dev/null +++ b/test/string.cb @@ -0,0 +1,16 @@ +import stdio; + +int +main(int argc, char **argv) +{ + printf(""); + printf(";"); + printf(";a"); + printf(";aa;b"); + printf(";\""); + printf(";\'"); + printf(";\a\b\e\f\n\r\t\v"); + printf(";\101\102\103\141\142\143"); + puts(""); + return 0; +} diff --git a/test/struct-semcheck.cb b/test/struct-semcheck.cb new file mode 100644 index 0000000..78a7b80 --- /dev/null +++ b/test/struct-semcheck.cb @@ -0,0 +1,32 @@ +struct a { +}; + +struct b { + struct a x; +}; + +struct c { + struct a x; + struct b y; +}; + +struct d { + struct c x; + struct c y; +}; + +// direct recursion with pointer +struct e { + struct e *ptr; +}; + +// indirect recursion with pointer +struct f { + struct g x; +}; + +struct g { + struct f * ptr; +}; + +int main(int argc, char **argv) { return 0; } diff --git a/test/struct-semcheck2.cb b/test/struct-semcheck2.cb new file mode 100644 index 0000000..845f300 --- /dev/null +++ b/test/struct-semcheck2.cb @@ -0,0 +1,5 @@ +struct a { + struct a x; +}; + +int main(int argc, char **argv) { return 0; } diff --git a/test/struct-semcheck3.cb b/test/struct-semcheck3.cb new file mode 100644 index 0000000..13ee49e --- /dev/null +++ b/test/struct-semcheck3.cb @@ -0,0 +1,5 @@ +// indirect recursion +struct a { struct b x; }; +struct b { struct a x; }; + +int main(int argc, char **argv) { return 0; } diff --git a/test/struct-semcheck4.cb b/test/struct-semcheck4.cb new file mode 100644 index 0000000..54ecf14 --- /dev/null +++ b/test/struct-semcheck4.cb @@ -0,0 +1,6 @@ +// indirect recursion +struct a { struct b x; }; +struct b { struct c x; }; +struct c { struct a x; }; + +int main(int argc, char **argv) { return 0; } diff --git a/test/struct.cb b/test/struct.cb new file mode 100644 index 0000000..ecf9841 --- /dev/null +++ b/test/struct.cb @@ -0,0 +1,17 @@ +import stdio; + +struct point { + int x; + int y; +}; + +int +main(int argc, char **argv) +{ + struct point pnt; + + pnt.x = 11; + pnt.y = 22; + printf("%d;%d\n", pnt.x, pnt.y); + return 0; +} diff --git a/test/sub.cb b/test/sub.cb new file mode 100644 index 0000000..11b0a75 --- /dev/null +++ b/test/sub.cb @@ -0,0 +1,45 @@ +import stdio; + +static int g = 8; +static int c; + +int +main(int argc, char **argv) +{ + int i = 1; + int j; + + printf("%d", 1 - 0); // 1 + printf(";%d", 3 - i); // 2 + i = 4; + j = 1; + printf(";%d", i - j); // 3 + printf(";%d", g - i); // 4 + i = 13; + printf(";%d", i - g); // 5 + printf(";%d", f(7)); // 6 + printf(";%d", f(9) - 1); // 7 + i = 1; + printf(";%d", f(10) - i); // 8 + c = 2; + printf(";%d", f(12) - c); // 9 + i = 11; + printf(";%d", f(i)); // 10 + i = 13; + j = 1; + printf(";%d", f(i) - j); // 11 + i = 15; + j = 4; + printf(";%d", i - f(j)); // 12 + i = 25; + j = 12; + printf(";%d", f(i) - f(j)); // 13 + puts(""); + return 0; +} + +int +f(int i) +{ + return i - 1; +} diff --git a/test/test.sh b/test/test.sh new file mode 100755 index 0000000..d08dcd2 --- /dev/null +++ b/test/test.sh @@ -0,0 +1,148 @@ +#!/bin/sh + +CBC=./cbc + +. ./shunit.sh + +assert_ok() { + assert_stdout "OK" $1 + assert_status 0 $1 +} + +assert_out() { + assert_stdout "$1" $2 + assert_status 0 $2 +} + +symbol_visibility() { + bin="$1" + sym="$2" + tmp=`readelf -s "$bin" | grep "$sym" | awk '{print $5}'` + if [ "$tmp" = "LOCAL" ] + then echo "private" + else echo "public" + fi +} + +assert_private() { + assert_eq "private" `symbol_visibility $1 $2` +} + +assert_status 0 ./zero +assert_status 1 ./one + +assert_out "Hello, World!" ./hello +assert_out "Hello, World!" ./hello2 +assert_out "Hello, World!" ./hello3 +assert_out "Hello, World!" ./hello4 + +assert_status 0 ./funcall0 +assert_status 0 ./funcall1 +assert_status 0 ./funcall2 +assert_status 0 ./funcall3 +assert_status 0 ./funcall4 +assert_out "1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30;31;32;33;34;35;36;37;38;39;40;41;42;43;44;45;46;47;48;49;50;51;52;53;54;55" ./funcall5 + +assert_out "$(/bin/echo -e ';;a;aa;b;";'\'';\a\b\0033\f\n\r\t\v;ABCabc')" ./string + +assert_out "1;2" ./param +assert_out "1;2" ./lvar1 +assert_out "1;2;3;4;5" ./lvar2 +assert_out "1;2" ./comm +assert_out "1;2" ./scomm +assert_private scomm static_common_symbol +assert_out "1;2" ./gvar +assert_out "1;2" ./sgvar +assert_private sgvar static_global_variable +assert_out "1;2" ./slvar +assert_private slvar static_variable +assert_out "1;2" ./slcomm +assert_private slcomm static_variable + +assert_out "1;2;3;4;5;6;7;8;9;10;11" ./add +assert_out "1;2;3;4;5;6;7;8;9;10;11;12;13" ./sub +assert_out "1;4;15" ./mul +assert_out "1;2;2;2" ./div +assert_out "0;0;1;4;7" ./mod + +assert_out "0;1;2;3;4" ./bitand +assert_out "0;1;2;3;2;6;8;10" ./bitor +assert_out "1;2;0;0;2" ./bitxor +assert_out "-1;-2;0" ./bitnot +assert_out "1;2;4;8;16" ./lshift +assert_out "16;8;4;2;1" ./rshift + +assert_out "1;0;0" ./logicalnot +assert_out "-1;0;1" ./unaryminus +assert_out "1;0;-1" ./unaryplus + +assert_out "0;1;0" ./eq +assert_out "1;0;1" ./neq +assert_out "1;0;0" ./gt +assert_out "0;0;1" ./lt +assert_out "1;1;0" ./gteq +assert_out "0;1;1" ./lteq + +assert_out "2;2" ./assign +assert_out "3;4;3;12;4;1;1;7;5;1;4" ./opassign +assert_out "0;1;2;2;3;3;4" ./inc +assert_out "4;3;2;2;1;1;0" ./dec + +assert_ok ./if1 +assert_ok ./if2 + +assert_out "OK;OK;OK;OK" ./condexpr +assert_out "0;0;0;2" ./logicaland +assert_out "0;1;1;1" ./logicalor + +assert_ok ./while1 +assert_ok ./while2 +assert_out "3;3;2;1;0" ./while3 +assert_ok ./while-break +assert_ok ./while-continue + +assert_ok ./dowhile1 +assert_ok ./dowhile2 +assert_out "3;3;2;1;0" ./dowhile3 +assert_ok ./dowhile-break +assert_ok ./dowhile-continue + +assert_out "3;3;2;1;0" ./for1 +assert_ok ./for-break +assert_ok ./for-continue + +assert_error $CBC break-semcheck.cb +assert_error $CBC continue-semcheck.cb + +assert_out "1;5;9" ./array +assert_out "11;22" ./struct +assert_status 0 ./struct-semcheck +assert_error $CBC struct-semcheck2.cb +assert_error $CBC struct-semcheck3.cb +assert_error $CBC struct-semcheck4.cb +assert_out "1;2;513" ./union # little endian +assert_status 0 ./union-semcheck +assert_error $CBC union-semcheck2.cb +assert_error $CBC union-semcheck3.cb +assert_error $CBC union-semcheck4.cb +assert_out "5;5" ./pointer +assert_out "1;2" ./ptrmemb +assert_out "OK" ./funcptr + +assert_out "2;64;-128;0" ./charops +assert_out "2;64;128;0" ./ucharops +assert_out "2;16384;-32768;0" ./shortops +assert_out "2;16384;32768;0" ./ushortops +assert_out "2;1073741824;-2147483648;0" ./intops +assert_out "2;1073741824;2147483648;0" ./uintops +assert_out "1;2;1073741824;-2147483648;0" ./longops # 32bit +assert_out "1;2;1073741824;2147483648;0" ./ulongops # 32bit + +assert_out "2" ./block +assert_out "25000000" ./cast +assert_out "1;2;3" ./defvar + +assert_error $CBC defun-semcheck.cb +assert_error $CBC funcall-semcheck.cb + +test_finished diff --git a/test/test2.cb b/test/test2.cb new file mode 100644 index 0000000..fe0a4f2 --- /dev/null +++ b/test/test2.cb @@ -0,0 +1,93 @@ +// various syntaxes + +// line comment + // line comment----- + + /* block comment */ +/* block +comment in + multiple lines */ + +import stdio; +import stdlib; +import unistd; + +char c; +short s; +int ii; +long l; +long long ll; + +unsigned char uc; +unsigned short us; +unsigned int ui; +unsigned long ul; +unsigned long long ull; + +int* p; +int** pp; +int*** ppp; +int**** pppp; +int***** ppppp; + +int[] a; +int[][] aa; +int[][][] aaa; +int[][][][] aaaa; +int[][][][][] aaaaa; + +int*[] pa; +int[]* ap; +int**[] ppa; +int*[]* pap; +int[]** app; +int[][]* aap; +int[]*[] apa; +int*[][] paa; + +struct file { + int fd; + char *path; +}; + +struct ifnode { + union node *cond; + union node *then_body; + union node *else_body; +}; + +struct stmt { + union node *expr; +}; + +union node { + struct ifnode ifnode; + struct stmt stmt; +}; + +typedef int myint; + +int +main(int argc, char[][] argv) +{ + ff(); + return f(1, 2, 3); +} + +void ff(void) { return; } + +int +f(int i, int j, int k) +{ + i++; + ++i; + i--; + --i; + printf("%d, %d, %p\n", 1, *(int*)j, (void*)h()); + return g(g(i, j % 18), 3 + 5 * 7); +} + +int g(int i, int j) { + ;; return i * h() * *((long*)&j) ; } + +myint h(void) { return 0; } diff --git a/test/test3.cb b/test/test3.cb new file mode 100644 index 0000000..9881449 --- /dev/null +++ b/test/test3.cb @@ -0,0 +1,7 @@ +// lookahead test (defstruct VS defvar) + +struct file { + int fd; +}; + +struct file f; diff --git a/test/test4.cb b/test/test4.cb new file mode 100644 index 0000000..05304d6 --- /dev/null +++ b/test/test4.cb @@ -0,0 +1,91 @@ +void printf(char *fmt, ...) { return; } +void sprintf(char *buf, char *fmt, ...) { return; } +void snprintf(char *buf, long size, char *fmt, ...) {} + +struct file { + int fd; + char *path; +}; + +int +f(void) +{ + int i = 3; + int j = 5 * 5; + int *p = &i; + + g(0); + g(+3); + g(-3); + g(+3U); + g(-3U); + g(+3UL); + g(-3UL); + + g(i + j); + g(i - j); + g(i * j); + g(i / j); + g(i % j); + g(i >> j); + g(i << j); + g(i & j); + g(i | j); + g(i ^ j); + + i += 1; + i -= 1; + i *= 1; + i /= 1; + i %= 1; + i &= 1; + i |= 1; + i ^= 1; + i <<= 1; + i >>= 1; + + g(+i); + g(-i); + + g(*p); + g(**&p); + + if (0) {} + if (0) {} else {} + if (0) { g(0); } + if (0) { g(0); } else { g(0); } + + if (1 && 0) {} + if (0 || 0) {} + if (1 == 0) {} + if (0 != 0) {} + if (1 < 0) {} + if (1 <= 0) {} + if (0 > 1) {} + if (0 >= 1) {} + + while (0) {} + while (0) { g(0); } + while (0) { continue; } + while (1) { break; } + + for (i = 0; i < 0; i++) {} + for (i = 0; i < 0; i++) { g(0); } + for (i = 0; i < 0; i++) { continue; } + for (i = 0; i < 0; i++) { break; } + + { + struct file f; + struct file *fp; + + f.fd = 5; + g(f.fd); + fp = &f; + fp->fd = 4; + g(fp->fd); + } + + return 1; +} + +void g(int i) {} diff --git a/test/ucharops.cb b/test/ucharops.cb new file mode 100644 index 0000000..50af540 --- /dev/null +++ b/test/ucharops.cb @@ -0,0 +1,18 @@ +import stdio; + +int +main(int argc, char **argv) +{ + unsigned char i = 1; + + i <<= 1; + printf("%hhu", i); + i <<= 5; + printf(";%hhu", i); + i <<= 1; + printf(";%hhu", i); + i <<= 1; + printf(";%hhu", i); + puts(""); + return 0; +} diff --git a/test/uintops.cb b/test/uintops.cb new file mode 100644 index 0000000..bc76d21 --- /dev/null +++ b/test/uintops.cb @@ -0,0 +1,18 @@ +import stdio; + +int +main(int argc, char **argv) +{ + unsigned int i = 1; + + i <<= 1; + printf("%u", i); + i <<= 29; + printf(";%u", i); + i <<= 1; + printf(";%u", i); + i <<= 1; + printf(";%u", i); + puts(""); + return 0; +} diff --git a/test/ulongops.cb b/test/ulongops.cb new file mode 100644 index 0000000..82b1334 --- /dev/null +++ b/test/ulongops.cb @@ -0,0 +1,19 @@ +import stdio; + +int +main(int argc, char **argv) +{ + unsigned long i = 1; + + printf("%lu", i); + i <<= 1; + printf(";%lu", i); + i <<= 61; + printf(";%lu", i); + i <<= 1; + printf(";%lu", i); + i <<= 1; + printf(";%lu", i); + puts(""); + return 0; +} diff --git a/test/unaryminus.cb b/test/unaryminus.cb new file mode 100644 index 0000000..23f9d3c --- /dev/null +++ b/test/unaryminus.cb @@ -0,0 +1,13 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 1; + int j = 0; + int k = -1; + + printf("%d;%d;%d", -i, -j, -k); + puts(""); + return 0; +} diff --git a/test/unaryplus.cb b/test/unaryplus.cb new file mode 100644 index 0000000..19173ab --- /dev/null +++ b/test/unaryplus.cb @@ -0,0 +1,13 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 1; + int j = 0; + int k = -1; + + printf("%d;%d;%d", +i, +j, +k); + puts(""); + return 0; +} diff --git a/test/union-semcheck.cb b/test/union-semcheck.cb new file mode 100644 index 0000000..49f49c9 --- /dev/null +++ b/test/union-semcheck.cb @@ -0,0 +1,32 @@ +union a { +}; + +union b { + union a x; +}; + +union c { + union a x; + union b y; +}; + +union d { + union c x; + union c y; +}; + +// direct recursion with pointer +union e { + union e *ptr; +}; + +// indirect recursion with pointer +union f { + union g x; +}; + +union g { + union f * ptr; +}; + +int main(int argc, char **argv) { return 0; } diff --git a/test/union-semcheck2.cb b/test/union-semcheck2.cb new file mode 100644 index 0000000..bca8a91 --- /dev/null +++ b/test/union-semcheck2.cb @@ -0,0 +1,5 @@ +union a { + union a x; +}; + +int main(int argc, char **argv) { return 0; } diff --git a/test/union-semcheck3.cb b/test/union-semcheck3.cb new file mode 100644 index 0000000..6cc15e2 --- /dev/null +++ b/test/union-semcheck3.cb @@ -0,0 +1,5 @@ +// indirect recursion +union a { union b x; }; +union b { union a x; }; + +int main(int argc, char **argv) { return 0; } diff --git a/test/union-semcheck4.cb b/test/union-semcheck4.cb new file mode 100644 index 0000000..1da1181 --- /dev/null +++ b/test/union-semcheck4.cb @@ -0,0 +1,6 @@ +// indirect recursion +union a { union b x; }; +union b { union c x; }; +union c { union a x; }; + +int main(int argc, char **argv) { return 0; } diff --git a/test/union.cb b/test/union.cb new file mode 100644 index 0000000..a43e9a4 --- /dev/null +++ b/test/union.cb @@ -0,0 +1,20 @@ +import stdio; + +union nums { + unsigned char[8] cs; + unsigned short s; + unsigned int i; + unsigned long l; +}; + +int +main(int argc, char **argv) +{ + union nums u; + + u.cs[0] = (unsigned char)1; + u.cs[1] = (unsigned char)2; + printf("%hhd;%hhd;%hd\n", u.cs[0], u.cs[1], u.s); + + return 0; +} diff --git a/test/ushortops.cb b/test/ushortops.cb new file mode 100644 index 0000000..85a9bdf --- /dev/null +++ b/test/ushortops.cb @@ -0,0 +1,18 @@ +import stdio; + +int +main(int argc, char **argv) +{ + unsigned short i = 1; + + i <<= 1; + printf("%hu", i); + i <<= 13; + printf(";%hu", i); + i <<= 1; + printf(";%hu", i); + i <<= 1; + printf(";%hu", i); + puts(""); + return 0; +} diff --git a/test/while-break.cb b/test/while-break.cb new file mode 100644 index 0000000..9fdba59 --- /dev/null +++ b/test/while-break.cb @@ -0,0 +1,13 @@ +import stdio; + +int +main(int argc, char **argv) +{ + while (1) { + break; + puts("NG"); + } + puts("OK"); + + return 0; +} diff --git a/test/while-continue.cb b/test/while-continue.cb new file mode 100644 index 0000000..975408a --- /dev/null +++ b/test/while-continue.cb @@ -0,0 +1,17 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i; + + i = 3; + while (i) { + i--; + continue; + puts("NG"); + } + puts("OK"); + + return 0; +} diff --git a/test/while1.cb b/test/while1.cb new file mode 100644 index 0000000..67feac2 --- /dev/null +++ b/test/while1.cb @@ -0,0 +1,12 @@ +import stdio; + +int +main(int argc, char **argv) +{ + while (0) { + puts("NG"); + return 1; + } + puts("OK"); + return 0; +} diff --git a/test/while2.cb b/test/while2.cb new file mode 100644 index 0000000..2b862b8 --- /dev/null +++ b/test/while2.cb @@ -0,0 +1,12 @@ +import stdio; + +int +main(int argc, char **argv) +{ + while (1) { + puts("OK"); + return 0; + } + puts("NG"); + return 1; +} diff --git a/test/while3.cb b/test/while3.cb new file mode 100644 index 0000000..960e6ba --- /dev/null +++ b/test/while3.cb @@ -0,0 +1,15 @@ +import stdio; + +int +main(int argc, char **argv) +{ + int i = 3; + + printf("%d", i); + while (i) { + printf(";%d", i); + i--; + } + printf(";%d\n", i); + return 0; +} diff --git a/test/zero.cb b/test/zero.cb new file mode 100644 index 0000000..e840c8e --- /dev/null +++ b/test/zero.cb @@ -0,0 +1,5 @@ +int +main(int argc, char **argv) +{ + return 0; +}