├── Sprak_Tests ├── bin │ └── Debug │ │ ├── code85.txt │ │ ├── code4.txt │ │ ├── code10.txt │ │ ├── code11.txt │ │ ├── code71.txt │ │ ├── code34.txt │ │ ├── code6.txt │ │ ├── code7.txt │ │ ├── code9.txt │ │ ├── code77.txt │ │ ├── code20.txt │ │ ├── code69.txt │ │ ├── code31.txt │ │ ├── code32.txt │ │ ├── code14.txt │ │ ├── code35.txt │ │ ├── code39.txt │ │ ├── code70.txt │ │ ├── code54.txt │ │ ├── code59.txt │ │ ├── code12.txt │ │ ├── code25.txt │ │ ├── code53.txt │ │ ├── code1.txt │ │ ├── code2.txt │ │ ├── code33.txt │ │ ├── code51.txt │ │ ├── code55.txt │ │ ├── code82.txt │ │ ├── code17.txt │ │ ├── code41.txt │ │ ├── code56.txt │ │ ├── code80.txt │ │ ├── code26.txt │ │ ├── code57.txt │ │ ├── code37.txt │ │ ├── code45.txt │ │ ├── code50.txt │ │ ├── code74.txt │ │ ├── code30.txt │ │ ├── code47.txt │ │ ├── code23.txt │ │ ├── code38.txt │ │ ├── code63.txt │ │ ├── code48.txt │ │ ├── code61.txt │ │ ├── code52.txt │ │ ├── code83.txt │ │ ├── Sprak_Tests.pdb │ │ ├── code36.txt │ │ ├── code28.txt │ │ ├── code42.txt │ │ ├── code72.txt │ │ ├── code58.txt │ │ ├── nunit.framework.dll │ │ ├── code18.txt │ │ ├── code60.txt │ │ ├── ProgrammingLanguageNr1.pdb │ │ ├── code84.txt │ │ ├── code68.txt │ │ ├── code65.txt │ │ ├── code62.txt │ │ ├── code73.txt │ │ ├── code75.txt │ │ ├── code5.txt │ │ ├── code67.txt │ │ ├── code44.txt │ │ ├── code24.txt │ │ ├── code13.txt │ │ ├── code40.txt │ │ ├── code49.txt │ │ ├── code76.txt │ │ ├── code16.txt │ │ ├── code19.txt │ │ ├── code21.txt │ │ ├── code86.txt │ │ ├── code64.txt │ │ ├── code78.txt │ │ ├── code8.txt │ │ ├── code81.txt │ │ ├── code3.txt │ │ ├── code79.txt │ │ ├── code46.txt │ │ ├── code27.txt │ │ ├── code15.txt │ │ ├── code29.txt │ │ ├── code22.txt │ │ ├── code43.txt │ │ └── code66.txt ├── tests │ ├── Scope_TEST.cs │ ├── MemorySpace_TEST.cs │ ├── ReturnValue_TEST.cs │ ├── AST_TEST.cs │ ├── ScopeBuilder_TEST.cs │ ├── Tokenizer_TEST.cs │ ├── FunctionDefinitionCreator_TEST.cs │ └── Parser_TEST.cs ├── AssemblyInfo.cs ├── obj │ └── Debug │ │ └── Sprak_Tests.csproj.FilesWrittenAbsolute.txt └── Sprak_Tests.csproj ├── dlls └── nunit.framework.dll ├── README ├── SprakProfiling ├── bin │ ├── Program2 │ ├── Program1 │ ├── Mem.sprak │ ├── hej.sprak │ ├── tryappend.sprak │ ├── Program3 │ └── Debug │ │ └── profile.sh ├── SprakProfiling.cs ├── Properties │ └── AssemblyInfo.cs ├── obj │ └── Debug │ │ └── SprakProfiling.csproj.FilesWrittenAbsolute.txt └── SprakProfiling.csproj ├── ProgrammingLanguageNr1 ├── bin │ └── Debug │ │ └── ProgrammingLanguageNr1.pdb ├── src │ ├── Symbols │ │ ├── Symbol.cs │ │ ├── VariableSymbol.cs │ │ └── FunctionSymbol.cs │ ├── 2. Parse and make AST │ │ ├── AST_MethodCall.cs │ │ ├── AST_ArrayEndSignal.cs │ │ ├── AST_LoopIncrementNode.cs │ │ ├── AST_LoopBlockNode.cs │ │ ├── AST_FunctionDefinitionNode.cs │ │ ├── AST_JumpToFunction.cs │ │ ├── AST_Assignment.cs │ │ ├── AST_LoopNode.cs │ │ ├── AST_IfNode.cs │ │ ├── AST_VariableDeclaration.cs │ │ ├── AST Tree structure overview.txt │ │ └── AST.cs │ ├── 3. Add external functions to tree │ │ ├── VariableDefinition.cs │ │ ├── FunctionDefinition.cs │ │ └── ExternalFunctionCreator.cs │ ├── 5. Run │ │ ├── Range.cs │ │ ├── MemorySpaceNodeListCache.cs │ │ ├── DefaultSprakRunner.cs │ │ ├── MemorySpace.cs │ │ └── Interpreter.cs │ ├── ListOfErrorMessages │ ├── Errors │ │ ├── Error.cs │ │ ├── ErrorHandler.cs │ │ └── ErrorHandler_TEST.cs │ ├── AssemblyInfo.cs │ ├── Expression evaluator (for testing) │ │ ├── ExpressionEvaluator.cs │ │ └── ExpressionEvaluator_TEST.cs │ ├── 1. Tokenize │ │ ├── Token.cs │ │ └── Tokenizer.cs │ ├── 4. Create scope tree │ │ ├── Scope.cs │ │ └── ScopeBuilder.cs │ ├── ASTPainter.cs │ └── FunctionDefinitionCreator.cs └── Sprak.csproj ├── .gitignore ├── LICENSE └── ProgrammingLanguageNr1.sln /Sprak_Tests/bin/Debug/code85.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code4.txt: -------------------------------------------------------------------------------- 1 | a * b -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code10.txt: -------------------------------------------------------------------------------- 1 | -10 - -5 -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code11.txt: -------------------------------------------------------------------------------- 1 | number x -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code71.txt: -------------------------------------------------------------------------------- 1 | (+ 2 3) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code34.txt: -------------------------------------------------------------------------------- 1 | number if = 5 -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code6.txt: -------------------------------------------------------------------------------- 1 | a * b + c * d + e -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code7.txt: -------------------------------------------------------------------------------- 1 | a * (b + c) / d -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code9.txt: -------------------------------------------------------------------------------- 1 | 10 + 5 * 3 + 1 -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code77.txt: -------------------------------------------------------------------------------- 1 | 2 | crash() 3 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code20.txt: -------------------------------------------------------------------------------- 1 | number a = 5 2 | print(a) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code69.txt: -------------------------------------------------------------------------------- 1 | 2 | fooo() 3 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code31.txt: -------------------------------------------------------------------------------- 1 | number f() 2 | return 3 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code32.txt: -------------------------------------------------------------------------------- 1 | number a = 2 | number b 3 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code14.txt: -------------------------------------------------------------------------------- 1 | number funky(number a, number b) { } -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code35.txt: -------------------------------------------------------------------------------- 1 | if(a) 2 | b 3 | else 4 | c 5 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code39.txt: -------------------------------------------------------------------------------- 1 | number a = 5 2 | number a = 10 3 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code70.txt: -------------------------------------------------------------------------------- 1 | 2 | loop from 1 to 3 | 4 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code54.txt: -------------------------------------------------------------------------------- 1 | loop (from 1 to 3) 2 | print(@) 3 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code59.txt: -------------------------------------------------------------------------------- 1 | array a = from 1 to 5 2 | print(Count(a)) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code12.txt: -------------------------------------------------------------------------------- 1 | number foo() 2 | 4 + 5 3 | 3 + 2 4 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code25.txt: -------------------------------------------------------------------------------- 1 | g() 2 | 3 | number g() 4 | print(42) 5 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code53.txt: -------------------------------------------------------------------------------- 1 | 2 | number a = 0 3 | 4 | a = 5 - "hej" 5 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code1.txt: -------------------------------------------------------------------------------- 1 | a = temp0 + 50001 2 | 3 | print(a) 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code2.txt: -------------------------------------------------------------------------------- 1 | if(a==5) 2 | print("hej!()()(){}{}!&&&") 3 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code33.txt: -------------------------------------------------------------------------------- 1 | number a 2 | number b 3 | a = 4 | number c 5 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code51.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | return 5 | 6 | print("hello") 7 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code55.txt: -------------------------------------------------------------------------------- 1 | 2 | array a = from 3 to 6 3 | 4 | print(a) 5 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code82.txt: -------------------------------------------------------------------------------- 1 | 2 | var xs = ["a" "b" "c"] 3 | print(xs[1]) 4 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code17.txt: -------------------------------------------------------------------------------- 1 | int x 2 | int € 3 | int y 4 | int @ 5 | int z 6 | in§ q -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code41.txt: -------------------------------------------------------------------------------- 1 | number a=5.0 2 | string s = "hej" 3 | void f() 4 | p =1 -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code56.txt: -------------------------------------------------------------------------------- 1 | 2 | array a = from 3 to 6 3 | 4 | print(a[2]) 5 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code80.txt: -------------------------------------------------------------------------------- 1 | 2 | if true 3 | print("hej") 4 | else if 5 | 6 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code26.txt: -------------------------------------------------------------------------------- 1 | print(foo()) 2 | 3 | number foo() 4 | return 500 5 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code57.txt: -------------------------------------------------------------------------------- 1 | 2 | print(foo()) 3 | 4 | number foo() 5 | 6 | end 7 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code37.txt: -------------------------------------------------------------------------------- 1 | number foo() 2 | 3 | end 4 | 5 | number bar() 6 | 7 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code45.txt: -------------------------------------------------------------------------------- 1 | 2 | array a 3 | 4 | a = newArray(5) 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code50.txt: -------------------------------------------------------------------------------- 1 | print(MAGIC_NUMBER) 2 | print(MAGIC_BOOL) 3 | print(MAGIC_STRING) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code74.txt: -------------------------------------------------------------------------------- 1 | 2 | number double(number x) 3 | return x * 2 4 | end 5 | 6 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code30.txt: -------------------------------------------------------------------------------- 1 | number foo(string a) 2 | print(a) 3 | end 4 | 5 | foo("hej", 42) 6 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code47.txt: -------------------------------------------------------------------------------- 1 | number a=10 2 | number b=a 3 | a++ 4 | b-- 5 | print(a) 6 | print(b) -------------------------------------------------------------------------------- /dlls/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eriksvedang/Sprak/HEAD/dlls/nunit.framework.dll -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code23.txt: -------------------------------------------------------------------------------- 1 | number a = 3 2 | number b = 10.5 3 | 4 | print(-a + -b) 5 | print(-(2 * a)) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code38.txt: -------------------------------------------------------------------------------- 1 | number foo() 2 | print("hej") 3 | 4 | 5 | number bar() { 6 | 7 | } -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code63.txt: -------------------------------------------------------------------------------- 1 | array a = [1] + [2,3] + [4] + [5,6,7] + (from 8 to 10) 2 | print("a: " + a) -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | A simple programming language made with simplicity and low learning curve in mind. Made by Erik Svedäng. -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code48.txt: -------------------------------------------------------------------------------- 1 | bool a 2 | bool b 3 | 4 | a = true 5 | b = false 6 | 7 | print(a) 8 | print(b) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code61.txt: -------------------------------------------------------------------------------- 1 | 2 | array words = ["fel", "hello", "fel", "fel"] 3 | 4 | print(words[1]) 5 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code52.txt: -------------------------------------------------------------------------------- 1 | 2 | number a; 3 | number b; 4 | number c; 5 | 6 | break 7 | 8 | print("hello") 9 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code83.txt: -------------------------------------------------------------------------------- 1 | 2 | void foo(number x, number y) 3 | print(x * y) 4 | end 5 | 6 | foo(10 50) 7 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/Sprak_Tests.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eriksvedang/Sprak/HEAD/Sprak_Tests/bin/Debug/Sprak_Tests.pdb -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code36.txt: -------------------------------------------------------------------------------- 1 | number a = 5 2 | 3 | if (false) 4 | a = 10 5 | else 6 | a = 15 7 | end 8 | 9 | print(a) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code28.txt: -------------------------------------------------------------------------------- 1 | number i = 0 2 | 3 | loop 4 | print(i) 5 | i = i + 1 6 | if(i == 10) 7 | break 8 | end 9 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code42.txt: -------------------------------------------------------------------------------- 1 | if(1.0) 2 | print("aj") 3 | end 4 | 5 | if(-5) 6 | print("ja") 7 | else 8 | print("nej") 9 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code72.txt: -------------------------------------------------------------------------------- 1 | string a = "hej" 2 | var answer = ThisFunctionTakesANumber(a) 3 | print("The answer was: " + answer) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code58.txt: -------------------------------------------------------------------------------- 1 | array a = getRange() 2 | loop(a) 3 | print(@) 4 | end 5 | 6 | number getRange() return from 10 to 13 end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eriksvedang/Sprak/HEAD/Sprak_Tests/bin/Debug/nunit.framework.dll -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code18.txt: -------------------------------------------------------------------------------- 1 | 2 | a b c d e 3 | 4 | int int int 5 | 6 | void foo() {} 7 | 8 | d e f 9 | 10 | foo() 11 | 12 | -------------------------------------------------------------------------------- /SprakProfiling/bin/Program2: -------------------------------------------------------------------------------- 1 | array a = from 0 to 2000 2 | number sum = 0 3 | 4 | loop a 5 | sum += @ 6 | end 7 | 8 | print(sum) 9 | 10 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code60.txt: -------------------------------------------------------------------------------- 1 | 2 | array names = ["erik", "heather", "johannes", "niklas"] 3 | 4 | loop names 5 | print(@) 6 | end 7 | 8 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/ProgrammingLanguageNr1.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eriksvedang/Sprak/HEAD/Sprak_Tests/bin/Debug/ProgrammingLanguageNr1.pdb -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code84.txt: -------------------------------------------------------------------------------- 1 | 2 | print("DONT PRINT ME") 3 | 4 | number double(number x) 5 | print("PRINT ME") 6 | return x * 2 7 | end 8 | 9 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code68.txt: -------------------------------------------------------------------------------- 1 | 2 | void print(string s) 3 | end 4 | 5 | 6 | print("hello") 7 | 8 | 9 | 10 | end 11 | 12 | 13 | fooo() 14 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code65.txt: -------------------------------------------------------------------------------- 1 | 2 | number x = 5 3 | 4 | number y() 5 | return 6 6 | end 7 | 8 | 9 | array a = [x, 5 + 1] 10 | 11 | print(a) 12 | 13 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/bin/Debug/ProgrammingLanguageNr1.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eriksvedang/Sprak/HEAD/ProgrammingLanguageNr1/bin/Debug/ProgrammingLanguageNr1.pdb -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code62.txt: -------------------------------------------------------------------------------- 1 | array a = [] 2 | 3 | a[0] = "abc" 4 | a[1] = true 5 | a[2] = false 6 | a[3] = 1 7 | a[4] = [1,2,3] 8 | 9 | loop a 10 | print(@) 11 | end 12 | -------------------------------------------------------------------------------- /SprakProfiling/bin/Program1: -------------------------------------------------------------------------------- 1 | 2 | loop from 1 to 3 3 | loop x from 1 to 5 4 | print(x) 5 | if x == 4 6 | break 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code73.txt: -------------------------------------------------------------------------------- 1 | 2 | number foo() 3 | return 10 + 32 4 | end 5 | 6 | number bar() 7 | return 123 + four() 8 | end 9 | 10 | number four() 11 | return 4 12 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code75.txt: -------------------------------------------------------------------------------- 1 | 2 | var numbers = [35, 10, 5] 3 | var sum = AddListOfNumbers(numbers) 4 | 5 | print("Sum: " + sum) 6 | 7 | 8 | 9 | void foo() 10 | 11 | end 12 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code5.txt: -------------------------------------------------------------------------------- 1 | number temp 2 | 3 | temp = 1 + 2 * 3 + 4 4 | 5 | number answer = 100 / 10 - 5 6 | 7 | if(4 > 5) { 8 | print("ja") 9 | } else { 10 | print("nej") 11 | } 12 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code67.txt: -------------------------------------------------------------------------------- 1 | 2 | string g1 = "hello" 3 | 4 | foo() 5 | 6 | string g2 = "world" 7 | 8 | 9 | void foo() 10 | print(g1) 11 | print(g2) 12 | end 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code44.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | string getString(number x) 4 | if(x > 0) 5 | return "a" 6 | end 7 | return "b" 8 | end 9 | 10 | 11 | print(getString(5)) 12 | print(getString(-5)) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code24.txt: -------------------------------------------------------------------------------- 1 | number a = 10 2 | number b = 15 3 | number c 4 | 5 | if(true) 6 | number a = 30 7 | b = 20 8 | number c = 100 9 | end 10 | 11 | print(a) 12 | print(b) 13 | print(c) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code13.txt: -------------------------------------------------------------------------------- 1 | number a 2 | number b 3 | void f(number n) {} 4 | 5 | a 6 | b 7 | f(42) 8 | 9 | void g(number a1, number a2) { f(4) + a2 - b } 10 | number h() { g(f(42)) } 11 | 12 | number x = g(a, b) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code40.txt: -------------------------------------------------------------------------------- 1 | loopFunction(0, 100) 2 | 3 | void loopFunction( number start, number stop ) 4 | start = start + 1 5 | end 6 | 7 | void foo( number now ) 8 | print("then") 9 | print(now) 10 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code49.txt: -------------------------------------------------------------------------------- 1 | bool evil=false 2 | number age=42 3 | string name="unknown" 4 | 5 | print("Evil: " + evil) 6 | print("Age: " + age) 7 | print("Name: " + name) 8 | print("abc" + (1 + 2 + 3) + "def") ### bug??? -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code76.txt: -------------------------------------------------------------------------------- 1 | 2 | var a = 10 3 | 4 | if a == 8 5 | print("nope") 6 | else if (a == 9) 7 | print("not this one") 8 | else if a == 10 9 | print("yup") 10 | else 11 | print("wrong") 12 | end 13 | 14 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code16.txt: -------------------------------------------------------------------------------- 1 | number x 2 | 3 | number answer = foo(4, 5) 4 | 5 | void foo(number x, number y) { 6 | x + y 7 | } 8 | 9 | 10 | number a 11 | 12 | if (a) { 13 | number a 14 | } else { 15 | number b 16 | } -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code19.txt: -------------------------------------------------------------------------------- 1 | print( (2 + 2) * 5 ) 2 | print( -2 * (5 - 3) ) 3 | print( 100 / 10 + 1 ) 4 | print( (-10 + -10) ) 5 | print( (50 / 10) - (3 * 2) ) 6 | print( -0.5 + 1 ) 7 | print( -0.25 * (1 + 1) ) 8 | print( 100 + 0.1 ) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code21.txt: -------------------------------------------------------------------------------- 1 | number a 2 | number b 3 | number c 4 | number d 5 | 6 | a = 10 7 | b = 5 8 | c = 2 9 | d = a + b + c # = 17 10 | 11 | print(a) 12 | print(10 * c) 13 | print(d * 2 + -4) 14 | print((a * b * c) / 2.5) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code86.txt: -------------------------------------------------------------------------------- 1 | array a0 = [] 2 | a0[0] = 0 3 | print(GetIndexes(a0)) 4 | array a1 = [0] 5 | print(GetIndexes(a1)) 6 | array a2 = [0] + [0] 7 | print(GetIndexes(a2)) 8 | string a3 = "ab" 9 | print(GetIndexes(a3)) 10 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code64.txt: -------------------------------------------------------------------------------- 1 | array a = ["text", "20", -1.0, 3.5, true, false] 2 | 3 | loop a 4 | print("--- " + @ + " ---") 5 | print("string: " + toString(@)) 6 | print("number: " + toNumber(@)) 7 | print("bool: " + toBool(@)) 8 | end -------------------------------------------------------------------------------- /SprakProfiling/bin/Mem.sprak: -------------------------------------------------------------------------------- 1 | 2 | var a 3 | var sum = 0 4 | 5 | number getVal(array b, number i) 6 | return b[i] 7 | end 8 | 9 | loop from 1 to 2000 10 | a = [1,2,3,4,5] 11 | sum += getVal(a, 2) 12 | end 13 | 14 | print(sum) 15 | -------------------------------------------------------------------------------- /SprakProfiling/bin/hej.sprak: -------------------------------------------------------------------------------- 1 | 2 | 3 | var sum = 0 4 | 5 | loop i in from 1 to 60 6 | loop j in from 1 to 60 7 | loop k in from 1 to 60 8 | sum += k 9 | end 10 | end 11 | end 12 | 13 | print("Sum = " + sum) 14 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code78.txt: -------------------------------------------------------------------------------- 1 | void Foo(string name) 2 | 3 | if(name == "Forward") 4 | print("f") 5 | else if(name == "Left") 6 | print("l") 7 | else if(name == "Right") 8 | print("r") 9 | else 10 | print("e") 11 | end 12 | 13 | end -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code8.txt: -------------------------------------------------------------------------------- 1 | 2 | (a) * (b) 3 | 4 | expr1 = (6 + 4) * 7 5 | expr2 = (2 * 5) + (30 * 3) 6 | expr3 = 88 + (3 * (3 + 1)) 7 | 8 | expr4 = ((2 + 3) > (2 + 2)) 9 | 10 | expr5 = ( ((45 / 23) < (33 * 10)) || ((100 + 50) >= (450 - 20)) ) -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code81.txt: -------------------------------------------------------------------------------- 1 | 2 | if false and false 3 | print("nope") 4 | end 5 | 6 | if true and true 7 | print("yep") 8 | end 9 | 10 | if true and false 11 | print("nope") 12 | end 13 | 14 | if false and true 15 | print("nope") 16 | end 17 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code3.txt: -------------------------------------------------------------------------------- 1 | 2 | # This code should actually do something... 3 | 4 | int a = 5 5 | int b = 8 6 | int c 7 | 8 | c = a + b 9 | 10 | if(c > 3 * 3 + 1) { 11 | print("a + b > 10") # Can you ignore this comment? 12 | } 13 | 14 | print("End of program") 15 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code79.txt: -------------------------------------------------------------------------------- 1 | void Foo(string name) 2 | 3 | if(name == "Forward") 4 | print("f") 5 | else if(name == "Left") 6 | print("l") 7 | else if(name == "Right") 8 | print("r") 9 | else 10 | print("e") 11 | end 12 | 13 | print("buu") 14 | 15 | end -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/Symbols/Symbol.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Text; 4 | 5 | namespace ProgrammingLanguageNr1 6 | { 7 | public interface Symbol 8 | { 9 | string getName(); 10 | ReturnValueType getReturnValueType(); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code46.txt: -------------------------------------------------------------------------------- 1 | # comment 2 | print(1) # comment 3 | # comment 4 | if(1 < 0) # comment 5 | # comment 6 | else # comment 7 | # comment 8 | print(2)# comment 9 | end# comment 10 | # comment 11 | loop 12 | # comment 13 | print(3) # comment 14 | break# comment 15 | end# comment 16 | # comment -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST_MethodCall.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | // For calling methods on objects: 6 | // radio.PlaySound() 7 | 8 | public class AST_MethodCall 9 | { 10 | public AST_MethodCall () 11 | { 12 | } 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code27.txt: -------------------------------------------------------------------------------- 1 | number x = foo(4, 10) 2 | 3 | print(x) 4 | 5 | number foo(number x, number y) 6 | number a = times2(x) 7 | number b = half(y) 8 | return a - b 9 | end 10 | 11 | number times2(number n) 12 | number x = 0 13 | return n * 2 14 | end 15 | 16 | number half(number n) 17 | return n / 2 18 | end 19 | 20 | 21 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code15.txt: -------------------------------------------------------------------------------- 1 | 2 | number a 3 | number b 4 | 5 | void print() end 6 | void foo() end 7 | 8 | void function1() 9 | print(a) 10 | end 11 | 12 | void function2() 13 | print(a + b) 14 | end 15 | 16 | void function3() 17 | print(a + foo()) 18 | end 19 | 20 | void function4() 21 | print(foo() + b) 22 | end 23 | 24 | void function5() 25 | print(foo() + foo()) 26 | end 27 | 28 | 29 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code29.txt: -------------------------------------------------------------------------------- 1 | number square(number n) 2 | return n * n 3 | end 4 | 5 | number geometricSum(number start, number stop) 6 | if(start < stop) 7 | return start + geometricSum(start + 1, stop) 8 | else 9 | return stop 10 | end 11 | end 12 | 13 | number pythagoras(number a, number b) 14 | return (sqrt(square(a) + square(b))) 15 | end 16 | 17 | print(pythagoras(3, 4)) 18 | print(square(0.5)) 19 | print(geometricSum(5, 9)) -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST_ArrayEndSignal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace ProgrammingLanguageNr1 3 | { 4 | public class AST_ArrayEndSignal : AST 5 | { 6 | public AST_ArrayEndSignal(Token token) : base(token) 7 | { 8 | 9 | } 10 | 11 | public int ArraySize { 12 | get { 13 | return this.m_arraySize; 14 | } 15 | set { 16 | m_arraySize = value; 17 | } 18 | } 19 | 20 | 21 | private int m_arraySize; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code22.txt: -------------------------------------------------------------------------------- 1 | number a = 100 2 | number b = a / 2 # (50) 3 | number c = a * 2 # (200) 4 | 5 | if(a>b){ 6 | print("blå") 7 | } else { 8 | print("röd") 9 | } 10 | 11 | if(-b <= -b){ 12 | print("lila") 13 | }else{ 14 | print("gredelin") 15 | } 16 | 17 | if (c / 2 != b * 2) # false, they are the same 18 | { 19 | print("grön") 20 | } 21 | else 22 | { 23 | print("gul") 24 | } 25 | 26 | if(a > -1000 && a < 1000) { 27 | print("orange") 28 | } 29 | 30 | if(0) { 31 | print("blah") 32 | } 33 | 34 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST_LoopIncrementNode.cs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | using NUnit.Framework; 4 | using System; 5 | 6 | namespace ProgrammingLanguageNr1 7 | { 8 | public class AST_LoopIncrementNode : AST 9 | { 10 | public AST_LoopNode (Token token ) : base(token) 11 | { 12 | } 13 | 14 | public void setForeachArray(object foreachArray) { m_foreachArray = foreachArray; } 15 | public object getForeachArray() { return m_foreachArray; } 16 | 17 | object m_foreachArray; 18 | } 19 | } 20 | 21 | */ -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code43.txt: -------------------------------------------------------------------------------- 1 | print(rootAprox(9)) 2 | print(rootAprox(16)) 3 | 4 | number rootAprox(number n) 5 | number best = 0 6 | number smallestDif = n 7 | number x = 0 8 | loop 9 | number sqr = x * x 10 | number dif = abs(sqr - n) 11 | if(dif < smallestDif) 12 | smallestDif = dif 13 | best = x 14 | end 15 | x++ 16 | if x > n 17 | break 18 | end 19 | end 20 | return best 21 | end 22 | 23 | number abs(number x) 24 | if x < 0 25 | return -x 26 | else 27 | return x 28 | end 29 | end -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/3. Add external functions to tree/VariableDefinition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | [Serializable] 6 | public class VariableDefinition 7 | { 8 | public VariableDefinition() { } 9 | 10 | public VariableDefinition (string pVariableName, object pInitValue) 11 | { 12 | variableName = pVariableName; 13 | initValue = pInitValue; 14 | } 15 | 16 | public string variableName; 17 | public object initValue; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/5. Run/Range.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | public struct Range 6 | { 7 | public Range (int pStart, int pEnd, int pStep) : this() 8 | { 9 | this.start = pStart; 10 | this.end = pEnd; 11 | this.step = pStep; 12 | } 13 | 14 | public float start {get;set;} 15 | public float end {get;set;} 16 | public float step {get;set;} 17 | 18 | public override string ToString () 19 | { 20 | return string.Format ("(from {0} to {1})", start, end); 21 | } 22 | 23 | static Range NONE = new Range(0, 0, 0); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST_LoopBlockNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | public class AST_LoopBlockNode : AST 6 | { 7 | public AST_LoopBlockNode (Token token) : base(token) 8 | { 9 | } 10 | 11 | public override void ClearMemorySpaces () 12 | { 13 | base.ClearMemorySpaces (); 14 | if(m_scope != null) { 15 | m_scope.ClearMemorySpaces(); 16 | } 17 | } 18 | 19 | public void setScope(Scope scope) { m_scope = scope; } 20 | public Scope getScope() { return m_scope; } 21 | 22 | Scope m_scope; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Sprak_Tests/tests/Scope_TEST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | 6 | namespace ProgrammingLanguageNr1.tests 7 | { 8 | [TestFixture()] 9 | public class GlobalScope_TEST 10 | { 11 | [Test()] 12 | public void DefineFloatVariable () 13 | { 14 | Scope scope = new Scope(Scope.ScopeType.MAIN_SCOPE, "global scope"); 15 | VariableSymbol variableSymbol = new VariableSymbol("x", ReturnValueType.NUMBER); 16 | scope.define(variableSymbol); 17 | Assert.IsNotNull(scope.resolve("x")); 18 | } 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST_FunctionDefinitionNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | public class AST_FunctionDefinitionNode : AST 6 | { 7 | public AST_FunctionDefinitionNode (Token token) : base(token) 8 | { 9 | } 10 | 11 | public override void ClearMemorySpaces () 12 | { 13 | base.ClearMemorySpaces (); 14 | if(m_scope != null) { 15 | m_scope.ClearMemorySpaces(); 16 | } 17 | } 18 | 19 | public void setScope(Scope scope) { m_scope = scope; } 20 | public Scope getScope() { return m_scope; } 21 | 22 | Scope m_scope; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sprak_Tests/bin/Debug/code66.txt: -------------------------------------------------------------------------------- 1 | 2 | void add(array a, string s) 3 | number i = indexOfLastElement(a) 4 | a[i + 1] = s 5 | end 6 | 7 | number indexOfLastElement(array a) 8 | array indexes = GetIndexes(a) 9 | return indexes[Count(indexes) - 1] 10 | end 11 | 12 | void MyRemove(array a, string s) 13 | loop i in GetIndexes(a) 14 | if(a[i] == s) 15 | Remove(a, i) 16 | end 17 | end 18 | end 19 | 20 | array a 21 | 22 | a[2] = "johannes" 23 | 24 | add(a, "erik") 25 | add(a, "heather") 26 | add(a, "sinnet") 27 | add(a, "fredag") 28 | 29 | MyRemove(a, "erik") 30 | MyRemove(a, "sinnet") 31 | 32 | loop a 33 | print(@) 34 | end 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | *.DS_Store 3 | *.mdb 4 | *.pidb 5 | *.userprefs 6 | *.json 7 | *.xml 8 | *.exe 9 | test-results 10 | 11 | ProgrammingLanguageNr1.dll 12 | GameTypes.dll 13 | Sprak_Tests.dll 14 | ProgrammingLanguageNr1/obj/Debug/Sprak.csproj.FilesWrittenAbsolute.txt 15 | 16 | Sprak_Tests/obj/Release/Sprak_Tests.csproj.FilesWrittenAbsolute.txt 17 | 18 | SprakProfiling/obj/Release/SprakProfiling.csproj.FilesWrittenAbsolute.txt 19 | 20 | SprakProfiling/bin/Release/out.mlpd 21 | 22 | *.mlpd 23 | 24 | SprakProfiling/bin/Debug/out.mlpd 25 | 26 | Sprak_Tests/bin/Release/nunit.framework.dll 27 | 28 | ProgrammingLanguageNr1/obj/Release/Sprak.csproj.FilesWrittenAbsolute.txt 29 | -------------------------------------------------------------------------------- /SprakProfiling/bin/tryappend.sprak: -------------------------------------------------------------------------------- 1 | 2 | array tailArray; 3 | 4 | PrintArray(tailArray) 5 | 6 | Append(tailArray, "10") 7 | PrintArray(tailArray) 8 | 9 | Append(tailArray, "20") 10 | PrintArray(tailArray) 11 | 12 | Append(tailArray, "30") 13 | PrintArray(tailArray) 14 | 15 | #print(Count(tailArray)); 16 | 17 | 18 | Remove(tailArray, 2) 19 | PrintArray(tailArray) 20 | 21 | 22 | void PrintArray(array a) 23 | print(a) 24 | print("Count: " + Count(a)) 25 | loop k in GetIndexes(a) 26 | print(k + " => " + a[k]) 27 | end 28 | end 29 | 30 | 31 | Remove(tailArray, 10) 32 | 33 | #Remove(tailArray, 0); 34 | #print(Count(tailArray)); 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST_JumpToFunction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ProgrammingLanguageNr1 6 | { 7 | public class AST_FunctionCall : AST 8 | { 9 | public AST_FunctionCall(Token token) 10 | : base(token) 11 | { 12 | 13 | } 14 | 15 | AST_FunctionDefinitionNode m_functionDefinitionRef; 16 | 17 | public AST_FunctionDefinitionNode FunctionDefinitionRef 18 | { 19 | get { return m_functionDefinitionRef; } 20 | set { m_functionDefinitionRef = value; } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sprak_Tests/tests/MemorySpace_TEST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace ProgrammingLanguageNr1.tests 5 | { 6 | [TestFixture()] 7 | public class MemorySpace_TEST 8 | { 9 | [Test()] 10 | public void SaveVariableToMemorySpace () 11 | { 12 | MemorySpaceNodeListCache cache = new MemorySpaceNodeListCache(); 13 | 14 | AST root = new AST(); 15 | MemorySpace memorySpace = new MemorySpace("globals", root, new Scope(Scope.ScopeType.MAIN_SCOPE, "blah"), cache); 16 | object val = 5.9f; 17 | memorySpace.setValue("x", val); 18 | Assert.AreEqual(typeof(float), memorySpace.getValue("x").GetType()); 19 | Assert.AreEqual(5.9f, (float)memorySpace.getValue("x")); 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST_Assignment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ProgrammingLanguageNr1 6 | { 7 | public class AST_Assignment : AST 8 | { 9 | public AST_Assignment(Token token, string variableName) 10 | : base(token) 11 | { 12 | m_variableName = variableName; 13 | } 14 | 15 | string m_variableName; 16 | 17 | public string VariableName 18 | { 19 | get { return m_variableName; } 20 | } 21 | 22 | public override string ToString() 23 | { 24 | return "Assign to " + m_variableName + ""; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/5. Run/MemorySpaceNodeListCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ProgrammingLanguageNr1 5 | { 6 | public class MemorySpaceNodeListCache 7 | { 8 | public MemorySpaceNodeListCache () 9 | { 10 | } 11 | 12 | public bool hasCachedFunction(AST rootNode) { 13 | return m_lists.ContainsKey(rootNode); 14 | } 15 | 16 | public void addMemorySpaceList(List list, AST rootNode) { 17 | m_lists.Add(rootNode, list); 18 | } 19 | 20 | public List getList(AST rootNode) { 21 | return m_lists[rootNode]; 22 | } 23 | 24 | public void clear() { 25 | m_lists.Clear(); 26 | } 27 | 28 | Dictionary> m_lists = new Dictionary>(); 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST_LoopNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | public class AST_LoopNode : AST 6 | { 7 | public AST_LoopNode (Token token ) : base(token) 8 | { 9 | } 10 | 11 | public override void ClearMemorySpaces () 12 | { 13 | base.ClearMemorySpaces (); 14 | if(m_scope != null) { 15 | m_scope.ClearMemorySpaces(); 16 | } 17 | } 18 | 19 | public void setScope(Scope scope) { m_scope = scope; } 20 | public Scope getScope() { return m_scope; } 21 | 22 | //public void setForeachArray(object foreachArray) { m_foreachArray = foreachArray; } 23 | //public object getForeachArray() { return m_foreachArray; } 24 | 25 | Scope m_scope; 26 | //object m_foreachArray; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/Symbols/VariableSymbol.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | public class VariableSymbol : Symbol 6 | { 7 | public VariableSymbol (string name, ReturnValueType type) 8 | { 9 | m_name = name; 10 | m_returnValueType = type; 11 | } 12 | 13 | public string getName() 14 | { 15 | return m_name; 16 | } 17 | 18 | public ReturnValueType getReturnValueType() 19 | { 20 | return m_returnValueType; 21 | } 22 | 23 | public override string ToString() 24 | { 25 | return getReturnValueType() + " " + getName(); 26 | } 27 | 28 | string m_name; 29 | ReturnValueType m_returnValueType; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SprakProfiling/bin/Program3: -------------------------------------------------------------------------------- 1 | void foo(number max) 2 | 3 | print("Max: " + max) 4 | 5 | string a = "a" 6 | string b = "b" 7 | string c = "c" 8 | string d = "d" 9 | string e = "e" 10 | string f = "f" 11 | string g = "g" 12 | string h = "h" 13 | string i = "i" 14 | string j = "j" 15 | 16 | array word = [a, b, c, d, e, f, g, h, i, j] 17 | print("Type of word: " + type(word)) 18 | string flipped = "" 19 | print("Type of flipped: " + type(flipped)) 20 | 21 | loop from 0 to count(word) - 1 22 | var i = count(word) - @ 23 | string s = "" 24 | string w = word[@] 25 | loop from 0 to max 26 | s = s + w 27 | end 28 | flipped[i] = s 29 | end 30 | 31 | print("Indexes:") 32 | loop getIndexes(flipped) 33 | print(@) 34 | end 35 | 36 | print("Flipped string: " + toString(flipped)) 37 | 38 | end 39 | 40 | loop from 1 to 10 41 | foo(@) 42 | end -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Erik Svedäng, Johannes Gotlén 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | Permission is granted to anyone to use this software for any purpose, 7 | including commercial applications, and to alter it and redistribute it 8 | freely, subject to the following restrictions: 9 | 1. The origin of this software must not be misrepresented; you must not 10 | claim that you wrote the original software. If you use this software 11 | in a product, an acknowledgment in the product documentation would be 12 | appreciated but is not required. 13 | 2. Altered source versions must be plainly marked as such, and must not be 14 | misrepresented as being the original software. 15 | 3. This notice may not be removed or altered from any source distribution. 16 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST_IfNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | public class AST_IfNode : AST 6 | { 7 | public AST_IfNode (Token token ) : base(token) 8 | { 9 | } 10 | 11 | public void setScope(Scope scope) { 12 | #if DEBUG 13 | if (scope == null) { 14 | throw new Exception ("can't set m_scope to null for IfNode at line " + getToken ().LineNr); 15 | } 16 | #endif 17 | m_scope = scope; 18 | } 19 | 20 | public Scope getScope() { 21 | #if DEBUG 22 | if (m_scope == null) { 23 | throw new Exception ("m_scope is null for IfNode at line " + getToken ().LineNr); 24 | } 25 | #endif 26 | return m_scope; 27 | } 28 | 29 | public override void ClearMemorySpaces () 30 | { 31 | base.ClearMemorySpaces (); 32 | if(m_scope != null) { 33 | m_scope.ClearMemorySpaces(); 34 | } 35 | } 36 | 37 | Scope m_scope; 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Sprak_Tests/tests/ReturnValue_TEST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using ProgrammingLanguageNr1; 6 | using NUnit.Framework; 7 | 8 | namespace ProgrammingLanguageNr1.tests 9 | { 10 | // [TestFixture] 11 | // public class ReturnValue_TEST 12 | // { 13 | // [Test] 14 | // public void PackUnpackFloat() 15 | // { 16 | // object returnValue = 32.4f; 17 | // Assert.AreEqual(32.4f, (float)returnValue.Unpack(), 0.0001f); 18 | // Assert.AreEqual(32, Convert.ToInt32(returnValue.Unpack())); 19 | // } 20 | // 21 | // [Test] 22 | // public void PackUnpackInt() 23 | // { 24 | // object rv = new object(ReturnValueType.NUMBER, 32); 25 | // Assert.AreEqual(32.0f, (float)rv.Unpack(), 0.0001f); 26 | // Assert.AreEqual(32, Convert.ToInt32(rv.Unpack())); 27 | // } 28 | // } 29 | } 30 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/ListOfErrorMessages: -------------------------------------------------------------------------------- 1 | ERROR MESSAGES 2 | 3 | - TOKENIZER - 4 | Unrecognized character 5 | Can't have several period signs in a number 6 | 7 | - PARSER - 8 | Can't understand the word "___" 9 | Can't assign to @ 10 | Can't understand what the word "___" means here 11 | Can't understand the words at the end of this line 12 | Something is wrong with the argument list 13 | Ending parenthesis is missing in function call 14 | A comma is missing in argument list 15 | Something is wrong with the IF-statement 16 | The expression after = makes no sense 17 | Can't handle operator "___" 18 | Trying to define a function inside a function (are you missing the END word?) 19 | The code word "___" doesn't match the expected "___" 20 | 21 | - EXTERNAL FUNCTION CREATOR - 22 | There is already a function called "___" 23 | 24 | - SCOPE BUILDER - 25 | There is already a variable called '___' 26 | Can't find anything called 27 | 28 | - INTERPRETER - 29 | 30 | - MEMORY SPACE - 31 | Can't find variable with name '___' -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/Errors/Error.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | public class Error : Exception 6 | { 7 | public enum ErrorType { 8 | UNDEFINED, 9 | SYNTAX, 10 | LOGIC, 11 | SCOPE, 12 | RUNTIME 13 | } 14 | 15 | public Error(string pMessage) : base(pMessage) 16 | { 17 | m_type = ErrorType.UNDEFINED; 18 | m_lineNr = -1; 19 | m_linePosition = -1; 20 | } 21 | 22 | public Error (string pMessage, ErrorType type, int lineNr, int linePosition) : base(pMessage) 23 | { 24 | m_type = type; 25 | m_lineNr = lineNr; 26 | m_linePosition = linePosition; 27 | } 28 | 29 | public string getMessage() { return Message; } 30 | public int getLineNr() { return m_lineNr; } 31 | public int getLinePosition() { return m_linePosition; } 32 | public ErrorType getErrorType() { return m_type; } 33 | 34 | int m_lineNr, m_linePosition; 35 | ErrorType m_type; 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST_VariableDeclaration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ProgrammingLanguageNr1 6 | { 7 | public class AST_VariableDeclaration : AST 8 | { 9 | public AST_VariableDeclaration(Token token, ReturnValueType type, string name) 10 | : base(token) 11 | { 12 | m_type = type; 13 | m_name = name; 14 | } 15 | 16 | string m_name; 17 | ReturnValueType m_type; 18 | 19 | public ReturnValueType Type 20 | { 21 | get { return m_type; } 22 | set { m_type = value; } 23 | } 24 | 25 | public string Name 26 | { 27 | get { return m_name; } 28 | set { m_name = value; } 29 | } 30 | 31 | public override string ToString() 32 | { 33 | return base.ToString() + " " + m_name + " of type " + m_type; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/Symbols/FunctionSymbol.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Diagnostics; 5 | 6 | namespace ProgrammingLanguageNr1 7 | { 8 | public class FunctionSymbol : Scope, Symbol 9 | { 10 | public FunctionSymbol (Scope enclosingScope, string name, ReturnValueType type, AST functionDefinitionNode) 11 | : base(Scope.ScopeType.FUNCTION_SCOPE, name, enclosingScope) 12 | { 13 | Debug.Assert(enclosingScope != null); 14 | Debug.Assert(functionDefinitionNode != null); 15 | 16 | m_enclosingScope = enclosingScope; 17 | m_functionDefinitionNode = functionDefinitionNode; 18 | m_returnValueType = type; 19 | } 20 | 21 | public ReturnValueType getReturnValueType() 22 | { 23 | return m_returnValueType; 24 | } 25 | 26 | public AST getFunctionDefinitionNode() { return m_functionDefinitionNode; } 27 | 28 | private AST m_functionDefinitionNode; 29 | private ReturnValueType m_returnValueType; 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /SprakProfiling/bin/Debug/profile.sh: -------------------------------------------------------------------------------- 1 | # mono --profile=log:report,noalloc GameWorld2_TextView.exe 2 | 3 | LD_LIBRARY_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib mono --profile=log:calls GameWorld2_TextView.exe 4 | 5 | Overwrite outfile and limit stack depth: 6 | LD_LIBRARY_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib mono --profile=log:calls,calldepth=10,output=out.mlpd GameWorld2_TextView.exe 7 | 8 | No alloc: 9 | LD_LIBRARY_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib mono --profile=log:calls,calldepth=10,output=out.mlpd,noalloc,report GameWorld2_TextView.exe 10 | 11 | Alloc: 12 | LD_LIBRARY_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib mono --profile=log:calls,alloc,calldepth=10,output=out.mlpd,report GameWorld2_TextView.exe 13 | 14 | mono --gc=sgen --profile=log:heapshot MyProgram.exe 15 | 16 | 17 | 18 | LD_LIBRARY_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib mono --profile=log:calls,alloc,calldepth=10,output=out.mlpd,report ./SprakProfiling.exe ../Mem.sprak 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Sprak_Tests/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // Information about this assembly is defined by the following attributes. 5 | // Change them to the values specific to your project. 6 | 7 | [assembly: AssemblyTitle("Sprak_Tests")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("")] 12 | [assembly: AssemblyCopyright("Erik")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 19 | 20 | [assembly: AssemblyVersion("1.0.*")] 21 | 22 | // The following attributes are used to specify the signing key for the assembly, 23 | // if desired. See the Mono documentation for more information about signing. 24 | 25 | //[assembly: AssemblyDelaySign(false)] 26 | //[assembly: AssemblyKeyFile("")] 27 | 28 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // Information about this assembly is defined by the following attributes. 5 | // Change them to the values specific to your project. 6 | 7 | [assembly: AssemblyTitle("ProgrammingLanguageNr1")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("")] 12 | [assembly: AssemblyCopyright("")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 19 | 20 | [assembly: AssemblyVersion("1.0.*")] 21 | 22 | // The following attributes are used to specify the signing key for the assembly, 23 | // if desired. See the Mono documentation for more information about signing. 24 | 25 | //[assembly: AssemblyDelaySign(false)] 26 | //[assembly: AssemblyKeyFile("")] 27 | -------------------------------------------------------------------------------- /Sprak_Tests/obj/Debug/Sprak_Tests.csproj.FilesWrittenAbsolute.txt: -------------------------------------------------------------------------------- 1 | /Users/erik/Documents/Miman/github/Sprak/Sprak_Tests/bin/Debug/Sprak_Tests.dll.mdb 2 | /Users/erik/Documents/Miman/github/Sprak/Sprak_Tests/bin/Debug/Sprak_Tests.dll 3 | /Users/erik/Documents/Miman/github/Sprak/Sprak_Tests/obj/Debug/Sprak_Tests.dll 4 | /Users/erik/Documents/Miman/github/Sprak/Sprak_Tests/obj/Debug/Sprak_Tests.dll.mdb 5 | /Users/erik/Documents/Miman/github/Sprak/Sprak_Tests/bin/Debug/nunit.framework.dll 6 | /Users/erik/Documents/Miman/github/Sprak/Sprak_Tests/bin/Debug/ProgrammingLanguageNr1.dll 7 | /Users/erik/Documents/Miman/github/Sprak/Sprak_Tests/bin/Debug/ProgrammingLanguageNr1.dll.mdb 8 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/Sprak_Tests/bin/Debug/Sprak_Tests.dll.mdb 9 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/Sprak_Tests/bin/Debug/Sprak_Tests.dll 10 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/Sprak_Tests/obj/Debug/Sprak_Tests.dll 11 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/Sprak_Tests/obj/Debug/Sprak_Tests.dll.mdb 12 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/Sprak_Tests/bin/Debug/nunit.framework.dll 13 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/Sprak_Tests/bin/Debug/ProgrammingLanguageNr1.dll 14 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/Sprak_Tests/bin/Debug/ProgrammingLanguageNr1.dll.mdb 15 | -------------------------------------------------------------------------------- /SprakProfiling/SprakProfiling.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using ProgrammingLanguageNr1; 4 | using System.Diagnostics; 5 | using System.Collections.Generic; 6 | 7 | namespace SprakProfiling 8 | { 9 | class SprakProfiling 10 | { 11 | static void Main(string[] args) 12 | { 13 | string filename = ""; //"../Program1"; 14 | 15 | if (args.Length > 0) { 16 | filename = args [0]; 17 | } else { 18 | Console.ForegroundColor = ConsoleColor.Red; 19 | Console.WriteLine ("No program file given"); 20 | return; 21 | } 22 | 23 | TextReader tr = File.OpenText(filename); 24 | //StringReader programString = new StringReader("g()\nfloat g() {\n print(42)\n }"); 25 | 26 | FunctionDefinition[] functionDefinitions = new FunctionDefinition[] { 27 | new FunctionDefinition("void", "print", new string[] { "string" }, new string[] { "text" }, print, FunctionDocumentation.Default()) 28 | }; 29 | 30 | SprakRunner runner = new SprakRunner(tr, functionDefinitions); 31 | runner.run (int.MaxValue); 32 | } 33 | 34 | private static object print(object[] parameters) 35 | { 36 | object parameter0 = parameters[0]; 37 | Console.WriteLine (parameter0); 38 | return new object(); // void 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/Errors/ErrorHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ProgrammingLanguageNr1 5 | { 6 | public class ErrorHandler 7 | { 8 | public ErrorHandler () 9 | { 10 | } 11 | 12 | public void errorOccured(Error e) { 13 | m_errors.Add(e); 14 | } 15 | 16 | public void errorOccured(string message, Error.ErrorType errorType, int lineNr, int linePosition) { 17 | m_errors.Add(new Error(message, errorType, lineNr, linePosition)); 18 | } 19 | 20 | public void errorOccured(string message, Error.ErrorType errorType) { 21 | m_errors.Add(new Error(message, errorType, 0, 0)); 22 | } 23 | 24 | public void printErrorsToConsole() { 25 | 26 | if(getErrors().Count == 0) { 27 | Console.WriteLine("NO ERRORS"); 28 | } 29 | else { 30 | Console.WriteLine("ERROR MESSAGES: "); 31 | foreach (Error e in getErrors()) { 32 | Console.WriteLine( 33 | e.getErrorType() + 34 | " ERROR: " + 35 | e.getMessage() 36 | + " at line " + 37 | e.getLineNr() + 38 | " and position " + 39 | e.getLinePosition()); 40 | } 41 | } 42 | } 43 | 44 | public void Reset() 45 | { 46 | m_errors.Clear(); 47 | } 48 | 49 | public List getErrors() { return m_errors; } 50 | 51 | List m_errors = new List(); 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /SprakProfiling/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SprakProfiling")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("SprakProfiling")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5ca6d50d-5556-464a-9ae6-7ee5b0932d31")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST Tree structure overview.txt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | 4 | PROGRAM_ROOT 5 | statement list 6 | external func declarations ... 7 | 8 | 9 | expressions: 10 | 11 | OPERATOR 12 | left hand expression 13 | right hand expression 14 | 15 | 16 | 17 | function call: 18 | 19 | NAME 20 | ARGUMENT_LIST 21 | arg0 22 | arg1 23 | arg2 24 | etc... 25 | REFERENCE TO FUNCTION_DECLARATION 26 | 27 | 28 | ifthenelse: 29 | 30 | IF 31 | expression 32 | statement list if true 33 | statement list if false 34 | 35 | 36 | 37 | variable declaration: 38 | 39 | VAR_DECLARATION 40 | name of type 41 | name of variable 42 | 43 | 44 | 45 | function declaration: 46 | 47 | FUNC_DECLARATION 48 | 0 name of return type 49 | 1 name of function 50 | 2 parameter list 51 | 3 statement list 52 | 53 | 54 | 55 | return statement: 56 | 57 | RETURN 58 | 0 expression 59 | 1 RETURN! 60 | 61 | 62 | 63 | parameter list: 64 | 65 | PARAMETER LIST 66 | PARAMETER 67 | VAR_DECLARATION 68 | type 69 | name 70 | ASSIGN_SIGNAL 71 | 72 | 73 | 74 | assignment: 75 | 76 | ASSIGNMENT 77 | returnvalue 78 | assignment signal (contains name of variable to assign to) 79 | 80 | 81 | 82 | method call: 83 | 84 | 0 name of variable (pointing to object) 85 | 1 name of method to call on object 86 | 2 ARGUMENT LIST 87 | arg 0 88 | arg 1 89 | etc... 90 | 91 | 92 | 93 | */ 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Sprak_Tests/tests/AST_TEST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | 4 | namespace ProgrammingLanguageNr1.tests 5 | { 6 | [TestFixture()] 7 | public class AST_TEST 8 | { 9 | [Test()] 10 | public void SimpleAST () 11 | { 12 | Token plus = new Token(Token.TokenType.OPERATOR, "+"); 13 | Token one = new Token(Token.TokenType.NUMBER, "1"); 14 | Token two = new Token(Token.TokenType.NUMBER, "2"); 15 | 16 | AST root = new AST(plus); 17 | root.addChild(new AST(one)); 18 | root.addChild(new AST(two)); 19 | 20 | AST list = new AST(null); 21 | list.addChild(new AST(one)); 22 | list.addChild(new AST(two)); 23 | 24 | Console.WriteLine(root.getTreeAsString()); 25 | 26 | Assert.AreEqual("(+ 1 2)", root.getTreeAsString()); 27 | } 28 | 29 | [Test()] 30 | public void ReplaceASTNode () 31 | { 32 | AST parent = new AST(new Token(Token.TokenType.NAME, "parent")); 33 | AST child1 = new AST(new Token(Token.TokenType.NAME, "child1")); 34 | AST child2 = new AST(new Token(Token.TokenType.NAME, "child2")); 35 | AST child2a = new AST(new Token(Token.TokenType.NAME, "child2a")); 36 | AST child2b = new AST(new Token(Token.TokenType.NAME, "child2b")); 37 | 38 | parent.addChild(child1); 39 | parent.addChild(child2); 40 | child2.addChild(child2a); 41 | child2.addChild(child2b); 42 | 43 | //AST child3 = new AST(new Token(Token.TokenType.NAME, "child3")); 44 | 45 | Console.WriteLine(parent.findParent(child2b).getTokenString()); 46 | 47 | ASTPainter p = new ASTPainter(); 48 | p.PaintAST(parent); 49 | 50 | //Assert.Fail(); 51 | } 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /SprakProfiling/obj/Debug/SprakProfiling.csproj.FilesWrittenAbsolute.txt: -------------------------------------------------------------------------------- 1 | /Users/erik/Documents/Miman/github/Sprak/SprakProfiling/bin/Debug/SprakProfiling.exe.mdb 2 | /Users/erik/Documents/Miman/github/Sprak/SprakProfiling/bin/Debug/SprakProfiling.exe 3 | /Users/erik/Documents/Miman/github/Sprak/SprakProfiling/obj/Debug/SprakProfiling.exe 4 | /Users/erik/Documents/Miman/github/Sprak/SprakProfiling/obj/Debug/SprakProfiling.exe.mdb 5 | /Users/erik/Documents/Miman/github/Sprak/SprakProfiling/bin/Debug/ProgrammingLanguageNr1.dll 6 | /Users/erik/Documents/Miman/github/Sprak/SprakProfiling/bin/Debug/ProgrammingLanguageNr1.dll.mdb 7 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/SprakProfiling/bin/Debug/SprakProfiling.exe.mdb 8 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/SprakProfiling/bin/Debug/SprakProfiling.exe 9 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/SprakProfiling/obj/Debug/SprakProfiling.exe 10 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/SprakProfiling/obj/Debug/SprakProfiling.exe.mdb 11 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/SprakProfiling/bin/Debug/ProgrammingLanguageNr1.dll 12 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/SprakProfiling/bin/Debug/ProgrammingLanguageNr1.dll.mdb 13 | /Users/erik/Documents/Miman/github/Sprak/SprakProfiling/bin/Debug/Sprak.exe.mdb 14 | /Users/erik/Documents/Miman/github/Sprak/SprakProfiling/bin/Debug/Sprak.exe 15 | /Users/erik/Documents/Miman/github/Sprak/SprakProfiling/obj/Debug/Sprak.exe 16 | /Users/erik/Documents/Miman/github/Sprak/SprakProfiling/obj/Debug/Sprak.exe.mdb 17 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/SprakProfiling/bin/Debug/Sprak.exe.mdb 18 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/SprakProfiling/bin/Debug/Sprak.exe 19 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/SprakProfiling/obj/Debug/Sprak.exe 20 | /Users/erik/Projects/ElseHeartbreak/github/Sprak/SprakProfiling/obj/Debug/Sprak.exe.mdb 21 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/3. Add external functions to tree/FunctionDefinition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections.Generic; 4 | 5 | namespace ProgrammingLanguageNr1 6 | { 7 | public struct FunctionDefinition 8 | { 9 | public FunctionDefinition(string pReturnType, string pFunctionName, string[] pParameterTypes, string[] pParameterNames, ExternalFunctionCreator.OnFunctionCall pCallback, FunctionDocumentation pFunctionDocumentation) 10 | { 11 | returnType = pReturnType; 12 | functionName = pFunctionName; 13 | parameterTypes = pParameterTypes; 14 | parameterNames = pParameterNames; 15 | callback = pCallback; 16 | functionDocumentation = pFunctionDocumentation; 17 | hideInModifier = false; 18 | } 19 | 20 | public string returnType; 21 | public string functionName; 22 | public string[] parameterTypes; 23 | public string[] parameterNames; 24 | public ExternalFunctionCreator.OnFunctionCall callback; 25 | public FunctionDocumentation functionDocumentation; 26 | public bool hideInModifier; 27 | } 28 | 29 | public struct FunctionDocumentation 30 | { 31 | public static FunctionDocumentation Default() { 32 | return new FunctionDocumentation("no function description", new string[] {}); 33 | } 34 | 35 | public FunctionDocumentation(string pFunctionDescription, string[] pArgumentDescriptions) { 36 | _functionDescription = pFunctionDescription; 37 | _argumentDescriptions = pArgumentDescriptions; 38 | } 39 | 40 | public string GetFunctionDescription() { 41 | return _functionDescription; 42 | } 43 | 44 | public string GetArgumentDescription(int nr) 45 | { 46 | if(nr < 0 || nr > _argumentDescriptions.Length - 1) { 47 | return "No description"; 48 | } else { 49 | return _argumentDescriptions[nr]; 50 | } 51 | } 52 | 53 | private string _functionDescription; 54 | private string[] _argumentDescriptions; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /SprakProfiling/SprakProfiling.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.21022 7 | 2.0 8 | {679981A9-9D48-420F-A540-4C4332F02727} 9 | Exe 10 | Properties 11 | SprakProfiling 12 | Sprak 13 | 512 14 | v3.5 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | {07C3477F-7293-42CC-9B77-C2D66A91A45F} 43 | Sprak 44 | 45 | 46 | 47 | 48 | 55 | -------------------------------------------------------------------------------- /Sprak_Tests/tests/ScopeBuilder_TEST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using System.IO; 4 | 5 | namespace ProgrammingLanguageNr1.tests 6 | { 7 | [TestFixture()] 8 | public class ScopeBuilder_TEST 9 | { 10 | static ErrorHandler s_errorHandler = new ErrorHandler(); 11 | 12 | [Test()] 13 | public void DefineVariableFromCode () 14 | { 15 | Tokenizer t = new Tokenizer(s_errorHandler, true); 16 | Parser p = new Parser(t.process(File.OpenText("code11.txt")), s_errorHandler); 17 | p.process(); 18 | 19 | ScopeBuilder scopeBuilder = new ScopeBuilder(p.getAST(), s_errorHandler); 20 | scopeBuilder.process(); 21 | Scope globalScope = scopeBuilder.getGlobalScope(); 22 | 23 | Assert.IsNotNull(globalScope.resolve("x")); 24 | } 25 | 26 | [Test()] 27 | public void DefineFunction () 28 | { 29 | Tokenizer t = new Tokenizer(s_errorHandler, true); 30 | Parser p = new Parser(t.process(File.OpenText("code12.txt")), s_errorHandler); 31 | p.process(); 32 | 33 | ScopeBuilder scopeBuilder = new ScopeBuilder(p.getAST(), s_errorHandler); 34 | scopeBuilder.process(); 35 | Scope globalScope = scopeBuilder.getGlobalScope(); 36 | 37 | Assert.IsNotNull(globalScope.resolve("foo")); 38 | } 39 | 40 | [Test()] 41 | public void DeclareAndReferenceFunctionsAndVariables () 42 | { 43 | Tokenizer t = new Tokenizer(s_errorHandler, true); 44 | Parser p = new Parser(t.process(File.OpenText("code13.txt")), s_errorHandler); 45 | p.process(); 46 | 47 | ScopeBuilder scopeBuilder = new ScopeBuilder(p.getAST(), s_errorHandler); 48 | scopeBuilder.process(); 49 | } 50 | 51 | [Test()] 52 | public void DeclareVariableInSubscopes () 53 | { 54 | Tokenizer t = new Tokenizer(s_errorHandler, true); 55 | Parser p = new Parser(t.process(File.OpenText("code16.txt")), s_errorHandler); 56 | p.process(); 57 | 58 | ScopeBuilder scopeBuilder = new ScopeBuilder(p.getAST(), s_errorHandler); 59 | scopeBuilder.process(); 60 | } 61 | 62 | [Test()] 63 | public void ForgettingEndStatement () 64 | { 65 | Tokenizer t = new Tokenizer(s_errorHandler, true); 66 | ErrorHandler e = new ErrorHandler(); 67 | Parser p = new Parser(t.process(File.OpenText("code68.txt")), e); 68 | p.process(); 69 | 70 | ScopeBuilder scopeBuilder = new ScopeBuilder(p.getAST(), e); 71 | scopeBuilder.process(); 72 | 73 | e.printErrorsToConsole(); 74 | 75 | Assert.AreEqual(1, e.getErrors().Count); 76 | } 77 | 78 | 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /Sprak_Tests/Sprak_Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.21022 7 | 2.0 8 | {CEC707D6-CC5F-425B-8F7C-5E49803735A7} 9 | Library 10 | Sprak_Tests 11 | Sprak_Tests 12 | v3.5 13 | 14 | 15 | true 16 | full 17 | false 18 | bin\Debug 19 | DEBUG; 20 | prompt 21 | 4 22 | false 23 | 24 | 25 | none 26 | false 27 | bin\Release 28 | prompt 29 | 4 30 | false 31 | 32 | 33 | 34 | 35 | ..\dlls\nunit.framework.dll 36 | 37 | 38 | 3.5 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | {07C3477F-7293-42CC-9B77-C2D66A91A45F} 59 | Sprak 60 | 61 | 62 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/Expression evaluator (for testing)/ExpressionEvaluator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | 6 | // NOTE: The ExpressionEvaluator is just made for testing purposes 7 | 8 | public class ExpressionEvaluator 9 | { 10 | public ExpressionEvaluator (AST expressionTree) 11 | { 12 | m_expressionTree = expressionTree; 13 | } 14 | 15 | public float getValue() { 16 | return evaluate(m_expressionTree); 17 | } 18 | 19 | private float evaluate(AST tree) { 20 | float returnValue = 0; 21 | if(tree.getTokenType() == Token.TokenType.NUMBER) { 22 | returnValue = (float)System.Convert.ToDouble(tree.getTokenString()); 23 | } 24 | else if(tree.getTokenType() == Token.TokenType.OPERATOR) { 25 | if(tree.getTokenString() == "+") { 26 | returnValue = evaluate(tree.getChild(0)) + evaluate(tree.getChild(1)); 27 | } 28 | else if(tree.getTokenString() == "-") { 29 | returnValue = evaluate(tree.getChild(0)) - evaluate(tree.getChild(1)); 30 | } 31 | else if(tree.getTokenString() == "*") { 32 | returnValue = evaluate(tree.getChild(0)) * evaluate(tree.getChild(1)); 33 | } 34 | else if(tree.getTokenString() == "/") { 35 | returnValue = evaluate(tree.getChild(0)) / evaluate(tree.getChild(1)); 36 | } 37 | else if(tree.getTokenString() == "<") { 38 | returnValue = (evaluate(tree.getChild(0)) < evaluate(tree.getChild(1))) ? 1 : 0; 39 | } 40 | else if(tree.getTokenString() == ">") { 41 | returnValue = (evaluate(tree.getChild(0)) > evaluate(tree.getChild(1))) ? 1 : 0; 42 | } 43 | else if(tree.getTokenString() == "<=") { 44 | returnValue = (evaluate(tree.getChild(0)) <= evaluate(tree.getChild(1))) ? 1 : 0; 45 | } 46 | else if(tree.getTokenString() == ">=") { 47 | returnValue = (evaluate(tree.getChild(0)) >= evaluate(tree.getChild(1))) ? 1 : 0; 48 | } 49 | else if(tree.getTokenString() == "&&") { 50 | returnValue = (evaluate(tree.getChild(0)) != 0 && evaluate(tree.getChild(1)) != 0) ? 1 : 0; 51 | } 52 | else if(tree.getTokenString() == "||") { 53 | returnValue = (evaluate(tree.getChild(0)) != 0 || evaluate(tree.getChild(1)) != 0) ? 1 : 0; 54 | } 55 | else if(tree.getTokenString() == "!=") { 56 | returnValue = (evaluate(tree.getChild(0)) != evaluate(tree.getChild(1))) ? 1 : 0; 57 | } 58 | else if(tree.getTokenString() == "==") { 59 | returnValue = (evaluate(tree.getChild(0)) == evaluate(tree.getChild(1))) ? 1 : 0; 60 | } 61 | else { 62 | throw new InvalidOperationException("ExpressionEvaluator can't handle operators with string " + tree.getTokenString()); 63 | } 64 | } 65 | else { 66 | throw new InvalidOperationException("ExpressionEvaluator can't handle tokens of type " + tree.getTokenType()); 67 | } 68 | return returnValue; 69 | } 70 | 71 | AST m_expressionTree; 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/5. Run/DefaultSprakRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.IO; 5 | using System.Diagnostics; 6 | 7 | namespace ProgrammingLanguageNr1 8 | { 9 | public class DefaultSprakRunner 10 | { 11 | public DefaultSprakRunner(TextReader stream) 12 | { 13 | FunctionDefinition[] functionDefinitions = new FunctionDefinition[] { 14 | new FunctionDefinition("void", "print", new string[] { "var" }, new string[] { "the thing to print" }, new ExternalFunctionCreator.OnFunctionCall(print), FunctionDocumentation.Default()), 15 | new FunctionDefinition("number", "sqrt", new string[] { "number" }, new string[] { "f" }, new ExternalFunctionCreator.OnFunctionCall(sqrt), FunctionDocumentation.Default()) 16 | }; 17 | 18 | m_sprakRunner = new SprakRunner(stream, functionDefinitions); 19 | } 20 | 21 | public void printOutputToConsole() 22 | { 23 | Console.WriteLine("PROGRAM OUTPUT:"); 24 | foreach(string s in m_output) 25 | { 26 | Console.WriteLine(s); 27 | } 28 | } 29 | 30 | private object print(object[] parameters) 31 | { 32 | object parameter0 = parameters[0]; 33 | if (parameter0 == null) { 34 | throw new Exception ("Parameter0 is null!"); 35 | } 36 | m_output.Add(ReturnValueConversions.PrettyStringRepresenation(parameter0)); 37 | return VoidType.voidType; 38 | } 39 | 40 | private object sqrt(object[] parameters) 41 | { 42 | object parameter0 = parameters[0]; 43 | if (parameter0.GetType() == typeof(float)) 44 | { 45 | return (float)(Math.Sqrt((float)parameter0)); 46 | } 47 | else 48 | { 49 | throw new Error("Can't use sqrt on something that's not a number", Error.ErrorType.SYNTAX, 0, 0); 50 | } 51 | } 52 | 53 | private object f(object[] parameters) 54 | { 55 | return new object(); 56 | } 57 | 58 | public ErrorHandler getCompileTimeErrorHandler() { return m_sprakRunner.getCompileTimeErrorHandler(); } 59 | public ErrorHandler getRuntimeErrorHandler() { return m_sprakRunner.getRuntimeErrorHandler(); } 60 | 61 | public void run() 62 | { 63 | m_sprakRunner.run(); 64 | } 65 | 66 | public void run(int n) { 67 | m_sprakRunner.run(n); 68 | } 69 | 70 | public List Output 71 | { 72 | get { return m_output; } 73 | } 74 | 75 | public void printTree(bool printExecutionCounters) 76 | { 77 | m_sprakRunner.printTree(printExecutionCounters); 78 | } 79 | 80 | public object RunFunction(string functionName, object[] args) { 81 | return m_sprakRunner.RunFunction (functionName, args); 82 | } 83 | 84 | public SprakRunner sprakRunner { 85 | get { 86 | return m_sprakRunner; 87 | } 88 | } 89 | 90 | List m_output = new List(); 91 | SprakRunner m_sprakRunner; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sprak", "ProgrammingLanguageNr1\Sprak.csproj", "{07C3477F-7293-42CC-9B77-C2D66A91A45F}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SprakProfiling", "SprakProfiling\SprakProfiling.csproj", "{679981A9-9D48-420F-A540-4C4332F02727}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Relay", "..\Relay\Relay\Relay.csproj", "{9CFC0B9C-EC60-4488-9D4A-79F191AA5AFF}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameTypes", "..\GameTypes\GameTypes\GameTypes.csproj", "{EC63C4E3-C5B8-4EB1-90CD-2D2FC17801BD}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sprak_Tests", "Sprak_Tests\Sprak_Tests.csproj", "{CEC707D6-CC5F-425B-8F7C-5E49803735A7}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {07C3477F-7293-42CC-9B77-C2D66A91A45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {07C3477F-7293-42CC-9B77-C2D66A91A45F}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {07C3477F-7293-42CC-9B77-C2D66A91A45F}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {07C3477F-7293-42CC-9B77-C2D66A91A45F}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {679981A9-9D48-420F-A540-4C4332F02727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {679981A9-9D48-420F-A540-4C4332F02727}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {679981A9-9D48-420F-A540-4C4332F02727}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {679981A9-9D48-420F-A540-4C4332F02727}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {9CFC0B9C-EC60-4488-9D4A-79F191AA5AFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {9CFC0B9C-EC60-4488-9D4A-79F191AA5AFF}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {9CFC0B9C-EC60-4488-9D4A-79F191AA5AFF}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {9CFC0B9C-EC60-4488-9D4A-79F191AA5AFF}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {CEC707D6-CC5F-425B-8F7C-5E49803735A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {CEC707D6-CC5F-425B-8F7C-5E49803735A7}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {CEC707D6-CC5F-425B-8F7C-5E49803735A7}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {CEC707D6-CC5F-425B-8F7C-5E49803735A7}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {EC63C4E3-C5B8-4EB1-90CD-2D2FC17801BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {EC63C4E3-C5B8-4EB1-90CD-2D2FC17801BD}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {EC63C4E3-C5B8-4EB1-90CD-2D2FC17801BD}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {EC63C4E3-C5B8-4EB1-90CD-2D2FC17801BD}.Release|Any CPU.Build.0 = Release|Any CPU 40 | EndGlobalSection 41 | GlobalSection(MonoDevelopProperties) = preSolution 42 | StartupItem = SprakProfiling\SprakProfiling.csproj 43 | EndGlobalSection 44 | GlobalSection(SolutionProperties) = preSolution 45 | HideSolutionNode = FALSE 46 | EndGlobalSection 47 | EndGlobal 48 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/1. Tokenize/Token.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ProgrammingLanguageNr1 4 | { 5 | public class Token 6 | { 7 | public enum TokenType { 8 | 9 | NO_TOKEN_TYPE, 10 | EOF, 11 | NEW_LINE, 12 | COMMA, 13 | 14 | NAME, 15 | ARRAY_LOOKUP, 16 | OPERATOR, 17 | NUMBER, 18 | QUOTED_STRING, 19 | BOOLEAN_VALUE, 20 | ARRAY, 21 | DOT, 22 | 23 | ARRAY_END_SIGNAL, 24 | BUILT_IN_TYPE_NAME, 25 | ELSE, 26 | PARANTHESIS_LEFT, 27 | PARANTHESIS_RIGHT, 28 | BRACKET_LEFT, 29 | BRACKET_RIGHT, 30 | //BLOCK_BEGIN, 31 | BLOCK_END, 32 | STATEMENT_LIST, 33 | VAR_DECLARATION, 34 | FUNC_DECLARATION, 35 | NODE_GROUP, 36 | PARAMETER, 37 | FUNCTION_CALL, 38 | ASSIGNMENT, 39 | ASSIGNMENT_TO_ARRAY, 40 | IF, 41 | LOOP, 42 | IN, // for loops 43 | LOOP_BLOCK, 44 | LOOP_INCREMENT, 45 | GOTO_BEGINNING_OF_LOOP, 46 | BREAK, 47 | RETURN, 48 | PROGRAM_ROOT, 49 | COMMENT, 50 | FROM, 51 | TO, 52 | 53 | NOT, 54 | 55 | AND, 56 | OR, 57 | }; 58 | 59 | public Token (TokenType tokenType, string tokenString) 60 | { 61 | m_tokenType = tokenType; 62 | m_tokenString = tokenString; 63 | } 64 | 65 | public Token(TokenType tokenType, string tokenString, int lineNr, int linePosition) 66 | { 67 | m_tokenType = tokenType; 68 | m_tokenString = tokenString; 69 | m_lineNr = lineNr; 70 | m_linePosition = linePosition; 71 | } 72 | 73 | public TokenType getTokenType() { return m_tokenType; } 74 | public string getTokenString() { return m_tokenString; } 75 | 76 | public int LineNr { 77 | set { 78 | m_lineNr = value; 79 | } 80 | get { 81 | return m_lineNr; 82 | } 83 | } 84 | 85 | public int LinePosition { 86 | set { 87 | m_linePosition = value; 88 | } 89 | get { 90 | return m_linePosition; 91 | } 92 | } 93 | 94 | public override string ToString () 95 | { 96 | return getTokenType () + " " + getTokenString (); 97 | } 98 | 99 | public override bool Equals (object obj) 100 | { 101 | if (obj is Token) { 102 | Token other = obj as Token; 103 | 104 | if (this.getTokenString () == "") { 105 | return m_tokenType == other.getTokenType (); 106 | } else { 107 | return m_tokenString == other.getTokenString (); 108 | } 109 | } 110 | 111 | return false; 112 | } 113 | 114 | public override int GetHashCode () 115 | { 116 | return base.GetHashCode (); 117 | } 118 | 119 | protected TokenType m_tokenType; 120 | string m_tokenString; 121 | int m_lineNr = -1; 122 | int m_linePosition = -1; 123 | } 124 | 125 | public class TokenWithValue : Token { 126 | public TokenWithValue(TokenType tokenType, string tokenString, int lineNr, int linePosition, object pValue) 127 | : base(tokenType, tokenString, lineNr, linePosition) 128 | { 129 | m_value = pValue; 130 | } 131 | public TokenWithValue(TokenType pTokenType, string pTokenString, object pValue) : base(pTokenType, pTokenString) { 132 | m_value = pValue; 133 | } 134 | public object getValue() { 135 | return m_value; 136 | } 137 | private object m_value; 138 | } 139 | } 140 | 141 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/3. Add external functions to tree/ExternalFunctionCreator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace ProgrammingLanguageNr1 6 | { 7 | public class ExternalFunctionCreator 8 | { 9 | public delegate object OnFunctionCall(object[] pParameters); 10 | public Dictionary externalFunctions = new Dictionary(); 11 | 12 | public ExternalFunctionCreator(FunctionDefinition[] functionDefinitions) 13 | { 14 | if (functionDefinitions != null) 15 | { 16 | foreach (FunctionDefinition f in functionDefinitions) 17 | { 18 | defineFunction(f); 19 | } 20 | } 21 | } 22 | 23 | private void defineFunction(FunctionDefinition f) 24 | { 25 | if (externalFunctions.ContainsKey(f.functionName)) 26 | { 27 | throw new Error("There is already a function called '" + f.functionName + "'", Error.ErrorType.UNDEFINED, 0, 0); 28 | } 29 | 30 | AST parameterList = new AST(new Token(Token.TokenType.NODE_GROUP, "")); 31 | for (int i = 0; i < f.parameterTypes.Length; ++i) 32 | { 33 | parameterList.addChild(createParameterDefinition(f.parameterTypes[i], f.parameterNames[i])); 34 | } 35 | 36 | AST functionNode = createFunctionDefinitionNode(f.returnType, f.functionName, parameterList); 37 | 38 | m_builtInFunctions.Add(functionNode); 39 | externalFunctions.Add(f.functionName, f.callback); 40 | } 41 | 42 | private AST_FunctionDefinitionNode createFunctionDefinitionNode(string returnTypeName, string functionName, AST parameterList) 43 | { 44 | 45 | AST_FunctionDefinitionNode functionNode = 46 | new AST_FunctionDefinitionNode(new Token(Token.TokenType.FUNC_DECLARATION, "")); 47 | 48 | functionNode.addChild(new Token(Token.TokenType.BUILT_IN_TYPE_NAME, returnTypeName)); 49 | functionNode.addChild(new Token(Token.TokenType.NAME, functionName)); 50 | functionNode.addChild(parameterList); 51 | functionNode.addChild(new Token(Token.TokenType.STATEMENT_LIST, "")); 52 | 53 | return functionNode; 54 | } 55 | 56 | static public ReturnValueType GetReturnTypeFromString(string name) { 57 | switch (name.ToLower()) 58 | { 59 | case "number": 60 | return ReturnValueType.NUMBER; 61 | case "string": 62 | return ReturnValueType.STRING; 63 | case "void": 64 | return ReturnValueType.VOID; 65 | case "bool": 66 | return ReturnValueType.BOOL; 67 | case "array": 68 | return ReturnValueType.ARRAY; 69 | case "range": 70 | return ReturnValueType.RANGE; 71 | case "var": 72 | return ReturnValueType.UNKNOWN_TYPE; 73 | case "unknown_type": 74 | return ReturnValueType.UNKNOWN_TYPE; 75 | default: 76 | throw new Exception("GetReturnTypeFromString can't handle built in type with name " + name); 77 | } 78 | } 79 | 80 | private AST createParameterDefinition(string typeName, string variableName) 81 | { 82 | AST parameter = new AST(new Token(Token.TokenType.PARAMETER, "")); 83 | 84 | AST declaration = new AST_VariableDeclaration(new Token(Token.TokenType.VAR_DECLARATION, ""), GetReturnTypeFromString(typeName), variableName); 85 | AST assigment = new AST_Assignment(new Token(Token.TokenType.ASSIGNMENT, "="), variableName); 86 | 87 | parameter.addChild(declaration); 88 | parameter.addChild(assigment); 89 | 90 | return parameter; 91 | } 92 | 93 | public List FunctionASTs 94 | { 95 | get { return m_builtInFunctions; } 96 | } 97 | 98 | List m_builtInFunctions = new List(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/Sprak.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.21022 7 | 2.0 8 | {07C3477F-7293-42CC-9B77-C2D66A91A45F} 9 | Library 10 | ProgrammingLanguageNr1 11 | ProgrammingLanguageNr1 12 | v3.5 13 | 14 | 15 | true 16 | full 17 | false 18 | bin\Debug 19 | DEBUG 20 | prompt 21 | 4 22 | false 23 | 24 | 25 | none 26 | false 27 | bin\Release 28 | prompt 29 | 4 30 | false 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 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/2. Parse and make AST/AST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Diagnostics; 5 | 6 | namespace ProgrammingLanguageNr1 7 | { 8 | public class AST 9 | { 10 | public static int nrOfASTsInMemory = 0; 11 | 12 | public AST () { 13 | nrOfASTsInMemory++; 14 | } 15 | 16 | public AST (Token token) 17 | { 18 | m_token = token; 19 | nrOfASTsInMemory++; 20 | } 21 | 22 | ~AST() { 23 | nrOfASTsInMemory--; 24 | } 25 | 26 | public Token.TokenType getTokenType() { 27 | if (m_token != null) { 28 | return m_token.getTokenType(); 29 | } else { 30 | return Token.TokenType.NO_TOKEN_TYPE; 31 | } 32 | } 33 | 34 | public bool isNil() { return m_token == null; } 35 | 36 | public void addChild(AST childTree) { 37 | 38 | if (childTree == null) { 39 | //throw new Exception ("Child tree is null"); 40 | if(childTree == null) throw new Error("Failed to understand source code", Error.ErrorType.SYNTAX, -1, -1); 41 | } 42 | 43 | allocateListIfNecessary(); 44 | m_children.Add(childTree); 45 | } 46 | 47 | public void addChildFirst(AST childTree) { 48 | Debug.Assert(childTree != null); 49 | 50 | allocateListIfNecessary(); 51 | m_children.Insert(0, childTree); 52 | } 53 | 54 | public void addChildAtPosition(AST childTree, int pos) { 55 | Debug.Assert(childTree != null); 56 | 57 | allocateListIfNecessary(); 58 | m_children.Insert(pos, childTree); 59 | } 60 | 61 | private void allocateListIfNecessary() { 62 | if (m_children == null) { 63 | m_children = new List(); 64 | } 65 | } 66 | 67 | public void addChild(Token token) { 68 | AST childTree = new AST(token); 69 | addChild(childTree); 70 | } 71 | 72 | public AST findParent(AST ofThisChild) 73 | { 74 | Console.WriteLine("Going into " + getTokenString()); 75 | 76 | if(ofThisChild == null) { return null; } 77 | if(m_children == null) { return null; } 78 | 79 | int i = m_children.IndexOf(ofThisChild); 80 | if(i >= 0) { 81 | Console.WriteLine("Found " + ofThisChild.getTokenString()); 82 | return this; 83 | } 84 | else { 85 | foreach(AST child in m_children) { 86 | AST parent = child.findParent(ofThisChild); 87 | if(parent != null) { 88 | return parent; 89 | } 90 | } 91 | } 92 | return null; 93 | } 94 | 95 | public int getIndexOfChild(AST child) { 96 | if(m_children != null) { 97 | return m_children.IndexOf(child); 98 | } 99 | else { 100 | return -1; 101 | } 102 | } 103 | 104 | public AST getChild(int n) { 105 | allocateListIfNecessary(); 106 | Debug.Assert(n >= 0); 107 | Debug.Assert(n < m_children.Count); 108 | AST child = m_children[n]; 109 | Debug.Assert(child != null); 110 | return child; 111 | } 112 | 113 | public void removeChild(int index) { 114 | m_children.RemoveAt(index); 115 | } 116 | 117 | public List getChildren() { 118 | allocateListIfNecessary(); 119 | return m_children; 120 | } 121 | 122 | public string getTokenString() { 123 | return m_token != null ? m_token.getTokenString() : "nil"; 124 | } 125 | 126 | public Token getToken() { 127 | return m_token; 128 | } 129 | 130 | public override string ToString() 131 | { 132 | return getTokenString(); 133 | } 134 | 135 | public string getTreeAsString() { 136 | if (m_children == null || m_children.Count == 0) { 137 | return getTokenString(); 138 | } 139 | StringBuilder stringTree = new StringBuilder(); 140 | if ( !isNil() ) { 141 | stringTree.Append("("); 142 | stringTree.Append(getTokenString()); 143 | stringTree.Append(" "); 144 | } 145 | int i = 0; 146 | foreach (AST childTree in m_children) { 147 | if(i > 0) { stringTree.Append(" "); } 148 | i++; 149 | stringTree.Append(childTree.getTreeAsString()); 150 | } 151 | if ( !isNil() ) { 152 | stringTree.Append(")"); 153 | } 154 | return stringTree.ToString(); 155 | } 156 | 157 | public int Executions { 158 | get { 159 | return this.m_executions; 160 | } 161 | set { 162 | m_executions = value; 163 | } 164 | } 165 | 166 | public virtual void ClearMemorySpaces() { 167 | if(m_children == null) { 168 | return; 169 | } 170 | foreach(var child in m_children) { 171 | if(child != null) { 172 | child.ClearMemorySpaces(); 173 | } 174 | } 175 | } 176 | 177 | Token m_token; 178 | List m_children; 179 | int m_executions; 180 | } 181 | } 182 | 183 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/Expression evaluator (for testing)/ExpressionEvaluator_TEST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | 6 | namespace ProgrammingLanguageNr1 7 | { 8 | [TestFixture()] 9 | public class ExpressionEvaluator_TEST 10 | { 11 | static ErrorHandler s_errorHandler = new ErrorHandler(); 12 | 13 | [Test()] 14 | public void EvaluateSingleNumber () 15 | { 16 | AST tree = new AST(new Token(Token.TokenType.NUMBER, "42")); 17 | ExpressionEvaluator e = new ExpressionEvaluator(tree); 18 | Assert.AreEqual(42, e.getValue()); 19 | } 20 | 21 | [Test()] 22 | public void BasicEvaluation () 23 | { 24 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 25 | List tokens = tokenizer.process(File.OpenText("code9.txt")); 26 | 27 | Parser parser = new Parser(tokens, s_errorHandler); 28 | parser.process(); 29 | 30 | AST root = parser.getAST(); 31 | AST expressionTree = root.getChild(0).getChild(0); 32 | 33 | ExpressionEvaluator e1 = new ExpressionEvaluator(expressionTree); 34 | Assert.AreEqual(26, e1.getValue()); 35 | } 36 | 37 | [Test()] 38 | public void BooleanAND () 39 | { 40 | AST root = new AST(new Token(Token.TokenType.OPERATOR, "&&")); 41 | AST lhs = new AST(new Token(Token.TokenType.NUMBER, "1")); 42 | AST rhs = new AST(new Token(Token.TokenType.NUMBER, "0")); 43 | root.addChild(lhs); 44 | root.addChild(rhs); 45 | ExpressionEvaluator e = new ExpressionEvaluator(root); 46 | Assert.AreEqual(0, e.getValue()); 47 | } 48 | 49 | [Test()] 50 | public void BooleanOR () 51 | { 52 | AST root = new AST(new Token(Token.TokenType.OPERATOR, "||")); 53 | AST lhs = new AST(new Token(Token.TokenType.NUMBER, "1")); 54 | AST rhs = new AST(new Token(Token.TokenType.NUMBER, "0")); 55 | root.addChild(lhs); 56 | root.addChild(rhs); 57 | ExpressionEvaluator e = new ExpressionEvaluator(root); 58 | Assert.AreEqual(1, e.getValue()); 59 | } 60 | 61 | [Test()] 62 | public void BooleanEQUALS () 63 | { 64 | AST root = new AST(new Token(Token.TokenType.OPERATOR, "==")); 65 | AST lhs = new AST(new Token(Token.TokenType.NUMBER, "4500")); 66 | AST rhs = new AST(new Token(Token.TokenType.NUMBER, "4500")); 67 | root.addChild(lhs); 68 | root.addChild(rhs); 69 | ExpressionEvaluator e = new ExpressionEvaluator(root); 70 | Assert.AreEqual(1, e.getValue()); 71 | } 72 | 73 | [Test()] 74 | public void BooleanNOTEQUALS () 75 | { 76 | AST root = new AST(new Token(Token.TokenType.OPERATOR, "!=")); 77 | AST lhs = new AST(new Token(Token.TokenType.NUMBER, "4500")); 78 | AST rhs = new AST(new Token(Token.TokenType.NUMBER, "4500")); 79 | root.addChild(lhs); 80 | root.addChild(rhs); 81 | ExpressionEvaluator e = new ExpressionEvaluator(root); 82 | Assert.AreEqual(0, e.getValue()); 83 | } 84 | 85 | [Test()] 86 | public void BooleanLESSOREQUALS () 87 | { 88 | AST root = new AST(new Token(Token.TokenType.OPERATOR, "<=")); 89 | AST lhs = new AST(new Token(Token.TokenType.NUMBER, "3")); 90 | AST rhs = new AST(new Token(Token.TokenType.NUMBER, "3")); 91 | root.addChild(lhs); 92 | root.addChild(rhs); 93 | ExpressionEvaluator e = new ExpressionEvaluator(root); 94 | Assert.AreEqual(1, e.getValue()); 95 | } 96 | 97 | [Test()] 98 | public void BooleanLESSOREQUALS2 () 99 | { 100 | AST root = new AST(new Token(Token.TokenType.OPERATOR, "<=")); 101 | AST lhs = new AST(new Token(Token.TokenType.NUMBER, "4")); 102 | AST rhs = new AST(new Token(Token.TokenType.NUMBER, "3")); 103 | root.addChild(lhs); 104 | root.addChild(rhs); 105 | ExpressionEvaluator e = new ExpressionEvaluator(root); 106 | Assert.AreEqual(0, e.getValue()); 107 | } 108 | 109 | [Test()] 110 | public void BooleanGREATEROREQUALS () 111 | { 112 | AST root = new AST(new Token(Token.TokenType.OPERATOR, ">=")); 113 | AST lhs = new AST(new Token(Token.TokenType.NUMBER, "3")); 114 | AST rhs = new AST(new Token(Token.TokenType.NUMBER, "3")); 115 | root.addChild(lhs); 116 | root.addChild(rhs); 117 | ExpressionEvaluator e = new ExpressionEvaluator(root); 118 | Assert.AreEqual(1, e.getValue()); 119 | } 120 | 121 | [Test()] 122 | public void BooleanGREATEROREQUALS2 () 123 | { 124 | AST root = new AST(new Token(Token.TokenType.OPERATOR, ">=")); 125 | AST lhs = new AST(new Token(Token.TokenType.NUMBER, "4")); 126 | AST rhs = new AST(new Token(Token.TokenType.NUMBER, "3")); 127 | root.addChild(lhs); 128 | root.addChild(rhs); 129 | ExpressionEvaluator e = new ExpressionEvaluator(root); 130 | Assert.AreEqual(1, e.getValue()); 131 | } 132 | 133 | [Test()] 134 | public void HandleNegativeNumbers () 135 | { 136 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 137 | List tokens = tokenizer.process(File.OpenText("code10.txt")); 138 | 139 | Parser parser = new Parser(tokens, s_errorHandler); 140 | parser.process(); 141 | 142 | AST root = parser.getAST(); 143 | AST expressionTree = root.getChild(0).getChild(0); 144 | 145 | ExpressionEvaluator e = new ExpressionEvaluator(expressionTree); 146 | Assert.AreEqual(-5, e.getValue()); 147 | } 148 | } 149 | } 150 | 151 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/4. Create scope tree/Scope.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Diagnostics; 5 | 6 | namespace ProgrammingLanguageNr1 7 | { 8 | public class Scope 9 | { 10 | public enum ScopeType { 11 | MAIN_SCOPE, 12 | FUNCTION_SCOPE, 13 | LOOP_SCOPE, 14 | LOOP_BLOCK_SCOPE, 15 | IF_SCOPE 16 | } 17 | 18 | public static int nrOfScopesInMemory = 0; 19 | 20 | public Scope (ScopeType scopeType, string name) 21 | { 22 | m_scopeType = scopeType; 23 | m_name = name; 24 | nrOfScopesInMemory++; 25 | } 26 | 27 | public Scope(ScopeType scopeType, string name, Scope enclosingScope) 28 | { 29 | Debug.Assert(name != null && name != ""); 30 | Debug.Assert(enclosingScope != null); 31 | 32 | m_scopeType = scopeType; 33 | m_name = name; 34 | m_enclosingScope = enclosingScope; 35 | nrOfScopesInMemory++; 36 | } 37 | 38 | ~Scope() { 39 | nrOfScopesInMemory--; 40 | } 41 | 42 | public virtual Scope getEnclosingScope() { 43 | return m_enclosingScope; 44 | } 45 | 46 | public virtual string getName() { 47 | return m_name; 48 | } 49 | 50 | public Symbol resolve(string name) { 51 | if (m_symbols.ContainsKey(name)) { 52 | return m_symbols[name]; 53 | } 54 | else if (m_enclosingScope != null) { 55 | return m_enclosingScope.resolve(name); 56 | } 57 | else { 58 | return null; 59 | } 60 | } 61 | 62 | public Scope resolveToScope(string name) 63 | { 64 | if (m_symbols.ContainsKey(name)) 65 | { 66 | return this; 67 | } 68 | else if (m_enclosingScope != null) 69 | { 70 | return m_enclosingScope.resolveToScope(name); 71 | } 72 | else 73 | { 74 | return null; 75 | } 76 | } 77 | 78 | public virtual void define(Symbol symbol) { 79 | if(m_symbols.ContainsKey(symbol.getName())) { 80 | throw new ProgrammingLanguageNr1.Error("Program already contains a symbol called " + symbol.getName()); 81 | } 82 | m_symbols.Add(symbol.getName(), symbol); 83 | } 84 | 85 | public virtual bool isDefined(String symbolName) { 86 | return m_symbols.ContainsKey(symbolName); 87 | } 88 | 89 | public override string ToString() 90 | { 91 | return m_name; 92 | /* 93 | StringBuilder s = new StringBuilder(); 94 | 95 | s.Append("\nStart of " + getName()); 96 | int i = 0; 97 | foreach (Symbol symbol in m_symbols.Values) 98 | { 99 | if (i == 0) 100 | { 101 | s.Append("\n\t"); 102 | } 103 | s.Append(symbol.ToString()); 104 | if (i < m_symbols.Count - 1) 105 | { 106 | s.Append(", "); 107 | } 108 | i++; 109 | } 110 | s.Append("\nEnd of " + getName()); 111 | 112 | return s.ToString();*/ 113 | } 114 | 115 | public void PushMemorySpace(MemorySpace pMemorySpace) 116 | { 117 | if(m_memorySpaces.Count > 0 && m_memorySpaces.Peek() == pMemorySpace) { 118 | //Console.WriteLine("Pushing duplicate memory space, will ignore"); 119 | return; 120 | } 121 | 122 | //Console.WriteLine("Push " + pMemorySpace.getName() + " into scope " + this.getName()); 123 | m_memorySpaces.Push(pMemorySpace); 124 | } 125 | 126 | public MemorySpace PopMemorySpace() 127 | { 128 | return m_memorySpaces.Pop(); 129 | } 130 | 131 | public void setValue(string name, object val) { 132 | Scope scope = resolveToScope(name); 133 | if(scope == null) throw new Exception("scope is null, trying to set '" + name + "' to value " + val + " from scope '" + m_name + "'"); 134 | if(scope.m_memorySpaces == null) throw new Exception("scope.m_memorySpaces is null, trying to set " + name + " from scope " + m_name); 135 | if(scope.m_memorySpaces.Peek() == null) throw new Exception("scope.m_memorySpaces.Peek() is null, trying to set " + name + " from scope " + m_name); 136 | scope.m_memorySpaces.Peek().setValue(name, val); 137 | } 138 | 139 | public object getValue(string name) { 140 | Scope scope = resolveToScope(name); 141 | Debug.Assert(scope != null, "Can't resolve scope " + name); 142 | Stack memorySpaceStack = scope.m_memorySpaces; 143 | if(memorySpaceStack == null) { throw new Exception("memorySpaceStack is null"); } 144 | MemorySpace memorySpace = memorySpaceStack.Peek(); 145 | if(memorySpace == null) { throw new Exception("memorySpace is null"); } 146 | 147 | if(!memorySpace.hasValue(name)) { 148 | throw new Error("Can't access '" + name + "' (calling function too early?)"); 149 | } 150 | return memorySpace.getValue(name); 151 | } 152 | 153 | public ScopeType scopeType { 154 | get { 155 | return m_scopeType; 156 | } 157 | } 158 | 159 | public Stack memorySpaces { 160 | get { return m_memorySpaces; } 161 | } 162 | 163 | protected Dictionary m_symbols = new Dictionary(); 164 | protected Scope m_enclosingScope; 165 | protected string m_name; 166 | private Stack m_memorySpaces = new Stack(); 167 | private ScopeType m_scopeType; 168 | 169 | internal void ClearMemorySpaces() 170 | { 171 | m_memorySpaces.Clear(); 172 | } 173 | } 174 | } 175 | 176 | -------------------------------------------------------------------------------- /Sprak_Tests/tests/Tokenizer_TEST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | 7 | namespace ProgrammingLanguageNr1.tests 8 | { 9 | [TestFixture()] 10 | public class Tokenizer_TEST 11 | { 12 | static ErrorHandler s_errorHandler = new ErrorHandler(); 13 | 14 | [Test()] 15 | public void TokenizeCode1 () 16 | { 17 | TextReader reader = File.OpenText("code1.txt"); 18 | Tokenizer t = new Tokenizer(s_errorHandler, true); 19 | List tokens = t.process(reader); 20 | Assert.AreEqual(12, tokens.Count); 21 | Assert.AreEqual(tokens[0].getTokenType(), Token.TokenType.NAME); 22 | Assert.AreEqual(tokens[1].getTokenType(), Token.TokenType.ASSIGNMENT); 23 | Assert.AreEqual(tokens[2].getTokenType(), Token.TokenType.NAME); 24 | Assert.AreEqual(tokens[3].getTokenType(), Token.TokenType.OPERATOR); 25 | Assert.AreEqual(tokens[4].getTokenType(), Token.TokenType.NUMBER); 26 | Assert.AreEqual(tokens[5].getTokenType(), Token.TokenType.NEW_LINE); 27 | Assert.AreEqual(tokens[6].getTokenType(), Token.TokenType.NAME); 28 | Assert.AreEqual(tokens[7].getTokenType(), Token.TokenType.PARANTHESIS_LEFT); 29 | Assert.AreEqual(tokens[8].getTokenType(), Token.TokenType.NAME); 30 | Assert.AreEqual(tokens[9].getTokenType(), Token.TokenType.PARANTHESIS_RIGHT); 31 | Assert.AreEqual(tokens[10].getTokenType(), Token.TokenType.NEW_LINE); 32 | Assert.AreEqual(tokens[11].getTokenType(), Token.TokenType.EOF); 33 | } 34 | 35 | [Test()] 36 | public void TokenizeCode2 () 37 | { 38 | TextReader reader = File.OpenText("code2.txt"); 39 | Assert.IsNotNull(reader); 40 | Tokenizer t = new Tokenizer(s_errorHandler, true); 41 | List tokens = t.process(reader); 42 | 43 | Assert.AreEqual(tokens[0].getTokenType(), Token.TokenType.IF); 44 | Assert.AreEqual(tokens[1].getTokenType(), Token.TokenType.PARANTHESIS_LEFT); 45 | Assert.AreEqual(tokens[2].getTokenType(), Token.TokenType.NAME); 46 | Assert.AreEqual(tokens[3].getTokenType(), Token.TokenType.OPERATOR); 47 | Assert.AreEqual(tokens[4].getTokenType(), Token.TokenType.NUMBER); 48 | Assert.AreEqual(tokens[5].getTokenType(), Token.TokenType.PARANTHESIS_RIGHT); 49 | Assert.AreEqual(tokens[6].getTokenType(), Token.TokenType.NEW_LINE); 50 | Assert.AreEqual(tokens[7].getTokenType(), Token.TokenType.NAME); 51 | Assert.AreEqual(tokens[8].getTokenType(), Token.TokenType.PARANTHESIS_LEFT); 52 | Assert.AreEqual(tokens[9].getTokenType(), Token.TokenType.QUOTED_STRING); 53 | Assert.AreEqual(tokens[10].getTokenType(), Token.TokenType.PARANTHESIS_RIGHT); 54 | Assert.AreEqual(tokens[11].getTokenType(), Token.TokenType.NEW_LINE); 55 | Assert.AreEqual(tokens[12].getTokenType(), Token.TokenType.BLOCK_END); 56 | Assert.AreEqual(tokens[13].getTokenType(), Token.TokenType.EOF); 57 | } 58 | 59 | [Test()] 60 | public void TokenizeCode3() 61 | { 62 | TextReader reader = File.OpenText("code41.txt"); 63 | Assert.IsNotNull(reader); 64 | Tokenizer t = new Tokenizer(s_errorHandler, true); 65 | List tokens = t.process(reader); 66 | 67 | Assert.AreEqual(tokens[0].getTokenType(), Token.TokenType.BUILT_IN_TYPE_NAME); 68 | Assert.AreEqual(tokens[1].getTokenType(), Token.TokenType.NAME); 69 | Assert.AreEqual(tokens[2].getTokenType(), Token.TokenType.ASSIGNMENT); 70 | Assert.AreEqual(tokens[3].getTokenType(), Token.TokenType.NUMBER); 71 | Assert.AreEqual(tokens[4].getTokenType(), Token.TokenType.NEW_LINE); 72 | Assert.AreEqual(tokens[5].getTokenType(), Token.TokenType.BUILT_IN_TYPE_NAME); 73 | Assert.AreEqual(tokens[6].getTokenType(), Token.TokenType.NAME); 74 | Assert.AreEqual(tokens[7].getTokenType(), Token.TokenType.ASSIGNMENT); 75 | Assert.AreEqual(tokens[8].getTokenType(), Token.TokenType.QUOTED_STRING); 76 | Assert.AreEqual(tokens[9].getTokenType(), Token.TokenType.NEW_LINE); 77 | Assert.AreEqual(tokens[10].getTokenType(), Token.TokenType.BUILT_IN_TYPE_NAME); 78 | Assert.AreEqual(tokens[11].getTokenType(), Token.TokenType.NAME); 79 | Assert.AreEqual(tokens[12].getTokenType(), Token.TokenType.PARANTHESIS_LEFT); 80 | Assert.AreEqual(tokens[13].getTokenType(), Token.TokenType.PARANTHESIS_RIGHT); 81 | Assert.AreEqual(tokens[14].getTokenType(), Token.TokenType.NEW_LINE); 82 | Assert.AreEqual(tokens[15].getTokenType(), Token.TokenType.NAME); 83 | Assert.AreEqual(tokens[16].getTokenType(), Token.TokenType.ASSIGNMENT); 84 | Assert.AreEqual(tokens[17].getTokenType(), Token.TokenType.NUMBER); 85 | Assert.AreEqual(tokens[18].getTokenType(), Token.TokenType.EOF); 86 | } 87 | 88 | [Test()] 89 | public void TokenizeSingleQuotedCode () 90 | { 91 | StringReader programString = new StringReader( 92 | @"'hej'" 93 | ); 94 | 95 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 96 | List tokens = tokenizer.process(programString); 97 | 98 | tokens.ForEach (t => Console.WriteLine(t.getTokenType().ToString() + ", " + t.getTokenString())); 99 | 100 | Assert.AreEqual(2, tokens.Count); 101 | Assert.AreEqual(Token.TokenType.QUOTED_STRING, tokens[0].getTokenType()); 102 | Assert.AreEqual(Token.TokenType.EOF, tokens[1].getTokenType()); 103 | Assert.AreEqual("hej", tokens[0].getTokenString()); 104 | } 105 | 106 | [Test()] 107 | public void TokenizeDoubleQuotedCodeWithSingleQuoteInText () 108 | { 109 | StringReader programString = new StringReader( 110 | "\"can't\"" 111 | ); 112 | 113 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 114 | List tokens = tokenizer.process(programString); 115 | 116 | tokens.ForEach (t => Console.WriteLine(t.getTokenType().ToString() + ", " + t.getTokenString())); 117 | 118 | Assert.AreEqual(2, tokens.Count); 119 | Assert.AreEqual(Token.TokenType.QUOTED_STRING, tokens[0].getTokenType()); 120 | Assert.AreEqual(Token.TokenType.EOF, tokens[1].getTokenType()); 121 | Assert.AreEqual("can't", tokens[0].getTokenString()); 122 | } 123 | 124 | 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/ASTPainter.cs: -------------------------------------------------------------------------------- 1 | #define CANT_HANDLE_FANCY_CHARS 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace ProgrammingLanguageNr1 8 | { 9 | public class ASTPainter 10 | { 11 | private AST _root; 12 | private AST[] allNodes; 13 | private AST _currentNode; 14 | private AST _currentParentNode; 15 | private bool _currentNodeIsLastChild = true; 16 | private bool _printExecutions; 17 | 18 | public bool PrintExecutions { 19 | set { 20 | _printExecutions = value; 21 | } 22 | } 23 | 24 | public AST currentNode 25 | { 26 | set 27 | { 28 | _currentNode = value; 29 | _currentParentNode = GetParent(_currentNode); 30 | _currentNodeIsLastChild = IsLastChild(_currentNode, _currentParentNode == null ? _root : _currentParentNode); 31 | } 32 | get 33 | { 34 | return _currentNode; 35 | } 36 | } 37 | public AST currentParentNode 38 | { 39 | get { return _currentParentNode; } 40 | } 41 | public bool currentNodeIsLastChild 42 | { 43 | get { return _currentNodeIsLastChild; } 44 | } 45 | 46 | 47 | public void PaintAST(AST pRoot) 48 | { 49 | if (pRoot == null) { 50 | throw new Exception ("Can't paint pRoot since it's null"); 51 | } 52 | 53 | _root = pRoot; 54 | //build a list of all nodes 55 | List tmpAllNodes = new List(); 56 | BuildNodeList(pRoot, tmpAllNodes); 57 | allNodes = tmpAllNodes.ToArray(); 58 | 59 | //collect all leaf nodes 60 | List leafNodes = new List(); 61 | GetLeafNodes(pRoot, leafNodes); 62 | 63 | foreach (AST leaf in allNodes) 64 | { 65 | Console.WriteLine(BuildRow(leaf, pRoot)); 66 | } 67 | } 68 | 69 | private void GetLeafNodes(AST pCurrentNode, List pList) 70 | { 71 | List tmpList = pCurrentNode.getChildren(); 72 | if (tmpList == null || tmpList.Count <= 0) 73 | { 74 | pList.Add(pCurrentNode); 75 | } 76 | else 77 | { 78 | foreach (AST child in tmpList) 79 | { 80 | GetLeafNodes(child, pList); 81 | } 82 | } 83 | } 84 | private string GetNodeString( AST pNode ) 85 | { 86 | string result; 87 | result = pNode.getTokenType().ToString() + " : " + pNode.ToString(); 88 | if(_printExecutions) { 89 | result += " : " + pNode.Executions; 90 | } 91 | return result; 92 | } 93 | private string BuildRow(AST pLeaf, AST pRoot) 94 | { 95 | currentNode = pLeaf; 96 | StringBuilder resultString = new StringBuilder(); 97 | if (currentNode == _root) 98 | { 99 | PrependString(resultString, GetNodeString(currentNode) ); 100 | } 101 | else if (currentNode.getChildren().Count <= 0) { 102 | #if CANT_HANDLE_FANCY_CHARS 103 | PrependString(resultString, "-------- " + GetNodeString(currentNode) ); 104 | #else 105 | PrependString(resultString, "──────── " + GetNodeString(currentNode) ); 106 | #endif 107 | } 108 | else 109 | #if CANT_HANDLE_FANCY_CHARS 110 | PrependString(resultString, "-------- " + GetNodeString(currentNode) ); 111 | #else 112 | PrependString(resultString, "──────┬─ " + GetNodeString(currentNode) ); 113 | #endif 114 | 115 | if (currentNodeIsLastChild) 116 | { 117 | #if CANT_HANDLE_FANCY_CHARS 118 | PrependString(resultString, " |"); 119 | #else 120 | PrependString(resultString, " └"); 121 | #endif 122 | } 123 | else 124 | { 125 | #if CANT_HANDLE_FANCY_CHARS 126 | PrependString(resultString, " |"); 127 | #else 128 | PrependString(resultString, " ├"); 129 | #endif 130 | } 131 | currentNode = currentParentNode; 132 | while (currentParentNode != null) 133 | { 134 | if (currentNodeIsLastChild) 135 | { 136 | PrependString(resultString, " "); 137 | } 138 | else 139 | { 140 | #if CANT_HANDLE_FANCY_CHARS 141 | PrependString(resultString, " |"); 142 | #else 143 | PrependString(resultString, " │"); 144 | #endif 145 | } 146 | currentNode = currentParentNode; 147 | } 148 | 149 | return resultString.ToString(); 150 | } 151 | 152 | private void PrependString(StringBuilder pStringBuilder, string pString) 153 | { 154 | pStringBuilder.Insert(0, pString); 155 | } 156 | 157 | private AST GetParent(AST pLeaf) 158 | { 159 | foreach (AST a in allNodes) 160 | { 161 | foreach (AST child in a.getChildren()) 162 | { 163 | if (child == pLeaf) 164 | return a; 165 | } 166 | } 167 | return null; 168 | } 169 | private void BuildNodeList(AST pCurrentList, List pList) 170 | { 171 | if (pCurrentList == null) { 172 | Console.WriteLine ("Can't paint node, will return"); 173 | return; 174 | } 175 | 176 | pList.Add(pCurrentList); 177 | foreach(AST a in pCurrentList.getChildren()) 178 | { 179 | BuildNodeList(a, pList); 180 | } 181 | } 182 | 183 | private bool IsLastChild(AST pNode, AST pParent) 184 | { 185 | if (pParent == null) 186 | return true; 187 | if (pParent.getChildren().IndexOf(pNode) == pParent.getChildren().Count - 1) 188 | return true; 189 | return false; 190 | } 191 | 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/5. Run/MemorySpace.cs: -------------------------------------------------------------------------------- 1 | //#define WRITE_DEBUG_INFO 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | 7 | namespace ProgrammingLanguageNr1 8 | { 9 | public class MemorySpace 10 | { 11 | public static int nrOfMemorySpacesInMemory = 0; 12 | 13 | public MemorySpace (string name, AST root, Scope scope, MemorySpaceNodeListCache cache) 14 | { 15 | Debug.Assert(name != null); 16 | Debug.Assert(root != null); 17 | Debug.Assert(scope != null); 18 | Debug.Assert(cache != null); 19 | 20 | m_name = name; 21 | m_scope = scope; 22 | m_cache = cache; 23 | 24 | //Console.WriteLine("Creating list of nodes from tree: " + root.getTreeAsString()); 25 | 26 | if(m_cache.hasCachedFunction(root)) { 27 | //Console.WriteLine("Found cached list for " + m_name); 28 | m_nodes = m_cache.getList(root).ToArray(); 29 | } 30 | else { 31 | List list = new List(); 32 | addToList(list, root); 33 | m_cache.addMemorySpaceList(list, root); 34 | m_nodes = list.ToArray(); 35 | //Console.WriteLine("Created new list for " + m_name); 36 | } 37 | 38 | m_currentNode = -1; 39 | 40 | //Console.WriteLine("New memory space " + name + " has got " + list.Count + " AST nodes in its list."); 41 | 42 | nrOfMemorySpacesInMemory++; 43 | //Console.WriteLine("CREATED " + name); 44 | } 45 | 46 | ~MemorySpace() { 47 | nrOfMemorySpacesInMemory--; 48 | //Console.WriteLine("DELETED " + m_name); 49 | } 50 | 51 | private void addToList(List list, AST ast) 52 | { 53 | switch (ast.getTokenType()) 54 | { 55 | case Token.TokenType.FUNC_DECLARATION: 56 | addToList(list, ast.getChild(2)); 57 | addToList(list, ast.getChild(3)); 58 | break; 59 | 60 | case Token.TokenType.IF: 61 | addToList(list, ast.getChild(0)); 62 | list.Add(ast); 63 | #if WRITE_DEBUG_INFO 64 | Console.WriteLine(": " + ast.getTokenString() + " of type " + ast.getTokenType()); 65 | #endif 66 | break; 67 | 68 | case Token.TokenType.LOOP: 69 | list.Add(ast); 70 | #if WRITE_DEBUG_INFO 71 | Console.WriteLine(": " + ast.getTokenString() + " of type " + ast.getTokenType()); 72 | #endif 73 | break; 74 | 75 | case Token.TokenType.LOOP_BLOCK: 76 | list.Add(ast); 77 | #if WRITE_DEBUG_INFO 78 | Console.WriteLine(": " + ast.getTokenString() + " of type " + ast.getTokenType()); 79 | #endif 80 | break; 81 | 82 | default: 83 | addChildren(list, ast); 84 | #if WRITE_DEBUG_INFO 85 | Console.WriteLine(": " + ast.getTokenString() + " of type " + ast.getTokenType()); 86 | #endif 87 | list.Add(ast); 88 | break; 89 | } 90 | } 91 | 92 | private void addChildren(List list, AST ast) 93 | { 94 | List children = ast.getChildren(); 95 | if (children != null) 96 | { 97 | foreach (AST child in children) 98 | { 99 | addToList(list, child); 100 | } 101 | } 102 | } 103 | 104 | public void setValue(string name, object val) { 105 | Debug.Assert(name != null); 106 | Debug.Assert(val != null); 107 | 108 | if(m_valuesForStrings.ContainsKey(name)) { 109 | //Console.WriteLine("Setting the value with name " + name + " and type " + val.getReturnValueType() + " to " + val + " in " + getName()); 110 | m_valuesForStrings[name] = val; 111 | } else { 112 | //Console.WriteLine("Setting a new value with name " + name + " and type " + val.getReturnValueType() + " to " + val + " in " + getName()); 113 | m_valuesForStrings.Add(name, val); 114 | } 115 | } 116 | 117 | public bool hasValue(string name) 118 | { 119 | return m_valuesForStrings.ContainsKey(name); 120 | } 121 | 122 | public object getValue(string name) { 123 | Debug.Assert(name != null); 124 | 125 | if(!m_valuesForStrings.ContainsKey(name)) { 126 | throw new Error("Can't find variable with name '" + name + "' (forgot quotes?)"); 127 | } 128 | 129 | return m_valuesForStrings[name]; 130 | } 131 | 132 | public void PrintValues() 133 | { 134 | foreach (string name in m_valuesForStrings.Keys) 135 | { 136 | Console.WriteLine("\t\t" + name + " = " + m_valuesForStrings[name].ToString()); 137 | } 138 | } 139 | 140 | public string getName() { 141 | return m_name; 142 | } 143 | 144 | public AST CurrentNode 145 | { 146 | get 147 | { 148 | return m_nodes[m_currentNode]; 149 | } 150 | } 151 | 152 | public bool Next() 153 | { 154 | if (m_currentNode < m_nodes.Length - 1) 155 | { 156 | m_currentNode++; 157 | //Console.WriteLine(getName() + " increased iterator to " + m_currentNode); 158 | return true; 159 | } 160 | else 161 | { 162 | return false; 163 | } 164 | } 165 | 166 | public void MoveToStart() 167 | { 168 | m_currentNode = -1; 169 | } 170 | 171 | public void MoveToEnd() 172 | { 173 | m_currentNode = m_nodes.Length; 174 | } 175 | 176 | public void Jump(int steps) 177 | { 178 | m_currentNode += steps; 179 | } 180 | 181 | public void SetCurrentNode() 182 | { 183 | m_currentNode = m_nodes.Length; 184 | } 185 | 186 | public Scope Scope 187 | { 188 | get { return m_scope; } 189 | } 190 | 191 | public void TraceParentScopes () 192 | { 193 | Console.Write("Parent scopes of " + getName() + ": "); 194 | Scope s = m_scope; 195 | while(s != null) { 196 | Console.Write(s.getName() + ", "); 197 | s = s.getEnclosingScope(); 198 | } 199 | Console.WriteLine(""); 200 | } 201 | 202 | public void Delete() { 203 | m_name = ""; 204 | m_valuesForStrings = null; 205 | m_nodes = null; 206 | m_currentNode = -1; 207 | m_scope = null; 208 | m_cache = null; 209 | } 210 | 211 | string m_name; 212 | Dictionary m_valuesForStrings = new Dictionary(); 213 | AST[] m_nodes; 214 | int m_currentNode; 215 | Scope m_scope; 216 | MemorySpaceNodeListCache m_cache; 217 | } 218 | } 219 | 220 | -------------------------------------------------------------------------------- /Sprak_Tests/tests/FunctionDefinitionCreator_TEST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using NUnit.Framework; 5 | using System.IO; 6 | using ProgrammingLanguageNr1; 7 | using System.Reflection; 8 | 9 | namespace ProgrammingLanguageNr1.tests 10 | { 11 | public class DemoClass 12 | { 13 | [SprakAPI("returns two values", "floatA", "second float")] 14 | public float API_GetValues(float pFloatA, float pFloatB) { return (int)(pFloatA * pFloatB); } 15 | 16 | [SprakAPI("werw", "sdf")] 17 | public bool API_UseBool(bool pFloatA) { return pFloatA; } 18 | 19 | //no api 20 | public string API_NumberToString(float pFloat) { return pFloat.ToString(); } 21 | } 22 | 23 | [TestFixture] 24 | public class FunctionDefinitionCreator_TEST 25 | { 26 | [Test] 27 | public void BasicUsage() 28 | { 29 | DemoClass dc = new DemoClass(); 30 | FunctionDefinition[] defs = FunctionDefinitionCreator.CreateDefinitions(dc, typeof(DemoClass)); 31 | foreach (FunctionDefinition fd in defs) 32 | { 33 | if (fd.functionName == "NumberToString") 34 | { 35 | object rv = fd.callback(new object[]{ 1.5f }); 36 | Assert.AreEqual((1.5f).ToString(), (string)rv); 37 | } 38 | if (fd.functionName == "GetValues") 39 | { 40 | Console.WriteLine("retval " + fd.functionDocumentation.GetFunctionDescription() + ", " + 41 | fd.functionDocumentation.GetArgumentDescription(0) + 42 | ", " + fd.functionDocumentation.GetArgumentDescription(1)); 43 | object rv = fd.callback(new object[] { 3.0f, 4.0f }); 44 | Console.WriteLine("rv type: " + rv.GetType()); 45 | Assert.AreEqual(12f, (float)rv, 0.001f); 46 | } 47 | if (fd.functionName == "UseBool") 48 | { 49 | object rv = fd.callback(new object[] { true }); 50 | Assert.AreEqual(true, (bool)rv); 51 | } 52 | } 53 | } 54 | 55 | static FunctionDefinition GetPrintFunction() { 56 | return new FunctionDefinition ( 57 | "void", "print", 58 | new string[] { "string" }, new string[] { "text" }, 59 | o => { 60 | Console.WriteLine ((string)o[0]); 61 | return new object (); }, 62 | FunctionDocumentation.Default ()); 63 | } 64 | 65 | [Test] 66 | public void CallingFunctionWithWrongArgumentType_MANUAL_FUNCTION_DEFINITION() 67 | { 68 | TextReader programString = File.OpenText("code72.txt"); 69 | 70 | FunctionDefinition[] functionDefinitions = new FunctionDefinition[] { 71 | new FunctionDefinition( 72 | "number", "ThisFunctionTakesANumber", 73 | new string[] { "number" }, new string[] { "x" }, 74 | ThisFunctionTakesANumber, FunctionDocumentation.Default()), 75 | 76 | GetPrintFunction() 77 | }; 78 | 79 | SprakRunner program = new SprakRunner(programString, functionDefinitions); 80 | program.run(); 81 | 82 | Assert.AreEqual (0, program.getCompileTimeErrorHandler().getErrors().Count); 83 | } 84 | 85 | object ThisFunctionTakesANumber(object[] pArguments) { 86 | Console.WriteLine("pArguments[0] is of type " + pArguments[0].GetType()); 87 | return ((float)pArguments[0]) * 2.0f; 88 | } 89 | 90 | public class ClassWithFunction 91 | { 92 | [SprakAPI("Returns the number times two", "The number")] 93 | public float API_ThisFunctionTakesANumber(float x) { 94 | return x * 2.0f; 95 | } 96 | } 97 | 98 | [Test] 99 | public void CallingFunctionWithWrongArgumentType_USING_FUNCTION_DEFINITION_CREATOR() 100 | { 101 | TextReader programString = File.OpenText("code73.txt"); 102 | 103 | ClassWithFunction c = new ClassWithFunction (); 104 | FunctionDefinition[] funcDefs = FunctionDefinitionCreator.CreateDefinitions (c, typeof(ClassWithFunction)); 105 | 106 | List moreFunctionDefinitions = new List { 107 | GetPrintFunction () 108 | }; 109 | 110 | moreFunctionDefinitions.AddRange (funcDefs); 111 | 112 | SprakRunner program = new SprakRunner(programString, moreFunctionDefinitions.ToArray()); 113 | program.run(); 114 | 115 | Assert.AreEqual (0, program.getCompileTimeErrorHandler().getErrors().Count); 116 | } 117 | 118 | public class DemoClassThree 119 | { 120 | [SprakAPI("adds all the numbers", "the numbers")] 121 | public float API_AddListOfNumbers(object[] nums) 122 | { 123 | float sum = 0; 124 | foreach(float f in nums) { 125 | sum += f; 126 | } 127 | return sum; 128 | } 129 | } 130 | 131 | [Test] 132 | public void ArrayAsArgumentListTest() 133 | { 134 | DemoClassThree dc3 = new DemoClassThree(); 135 | FunctionDefinition[] defs = FunctionDefinitionCreator.CreateDefinitions(dc3, typeof(DemoClassThree)); 136 | Assert.AreEqual(1, defs.Length); 137 | 138 | List moreFunctionDefinitions = new List { 139 | GetPrintFunction () 140 | }; 141 | 142 | moreFunctionDefinitions.AddRange (defs); 143 | 144 | TextReader programString = File.OpenText("code75.txt"); 145 | SprakRunner program = new SprakRunner(programString, moreFunctionDefinitions.ToArray()); 146 | 147 | program.run(); 148 | 149 | foreach(var e in program.getRuntimeErrorHandler().getErrors()) { 150 | Console.WriteLine(e); 151 | } 152 | 153 | foreach(var e in program.getCompileTimeErrorHandler().getErrors()) { 154 | Console.WriteLine(e); 155 | } 156 | 157 | Assert.AreEqual (0, program.getRuntimeErrorHandler().getErrors().Count); 158 | Assert.AreEqual (0, program.getCompileTimeErrorHandler().getErrors().Count); 159 | } 160 | 161 | public class DemoClassFour 162 | { 163 | [SprakAPI("this function crashes")] 164 | public void API_crash() 165 | { 166 | throw new Error("Crashed!"); 167 | } 168 | } 169 | 170 | [Test] 171 | public void CallFunctionThatThrowsException() 172 | { 173 | DemoClassFour dc3 = new DemoClassFour(); 174 | FunctionDefinition[] defs = FunctionDefinitionCreator.CreateDefinitions(dc3, typeof(DemoClassFour)); 175 | Assert.AreEqual(1, defs.Length); 176 | 177 | List moreFunctionDefinitions = new List { 178 | GetPrintFunction () 179 | }; 180 | 181 | moreFunctionDefinitions.AddRange (defs); 182 | 183 | TextReader programString = File.OpenText("code77.txt"); 184 | SprakRunner program = new SprakRunner(programString, moreFunctionDefinitions.ToArray()); 185 | 186 | program.run(); 187 | 188 | Assert.AreEqual (0, program.getCompileTimeErrorHandler().getErrors().Count); 189 | Assert.AreEqual (1, program.getRuntimeErrorHandler().getErrors().Count); 190 | 191 | program.getRuntimeErrorHandler().printErrorsToConsole(); 192 | } 193 | 194 | 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/FunctionDefinitionCreator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Reflection; 6 | using ProgrammingLanguageNr1; 7 | 8 | namespace ProgrammingLanguageNr1 9 | { 10 | public class SprakAPI : Attribute 11 | { 12 | public string[] Values { get; set; } 13 | public SprakAPI(params string[] values) 14 | { 15 | this.Values = values; 16 | } 17 | } 18 | 19 | public delegate void Log(string pString); 20 | 21 | public class FunctionDefinitionCreator 22 | { 23 | public static Log logger; 24 | 25 | public static void Log (string pString) 26 | { 27 | if (logger != null) { 28 | logger(pString); 29 | } 30 | } 31 | 32 | public static FunctionDefinition[] CreateDefinitions (object pProgramTarget, Type pClassType) 33 | { 34 | //Log("Creating function definition targeted on " + pProgramTarget.ToString () + " on class of type " + pClassType.ToString ()); 35 | 36 | MethodInfo[] methodInfos = pClassType.GetMethods(); 37 | 38 | var documentation = CreateDocumentation (methodInfos); 39 | var functionDefinitions = CreateFunctionDefinitions (pProgramTarget, documentation, methodInfos); 40 | 41 | return functionDefinitions.ToArray(); 42 | } 43 | 44 | static Dictionary CreateDocumentation (MethodInfo[] methodInfos) 45 | { 46 | Dictionary functionDocumentations = new Dictionary(); 47 | 48 | foreach (MethodInfo methodInfo in methodInfos) { 49 | //Log("Found method " + methodInfo.Name); 50 | if (methodInfo.Name.StartsWith ("API_")) { 51 | SprakAPI[] helpAttributes = (SprakAPI[])methodInfo.GetCustomAttributes (typeof(SprakAPI), true); 52 | if (helpAttributes.Length > 0) { 53 | //Console.WriteLine("found " + String.Join( ",", help[0].Values)); 54 | List parameterHelp = new List (); 55 | for (int i = 1; i < helpAttributes [0].Values.Length; i++) { 56 | parameterHelp.Add (helpAttributes [0].Values [i]); 57 | } 58 | string shortname = methodInfo.Name.Substring (4); 59 | FunctionDocumentation fd = new FunctionDocumentation (helpAttributes [0].Values [0], parameterHelp.ToArray ()); 60 | functionDocumentations.Add (shortname, fd); 61 | } 62 | } 63 | } 64 | 65 | return functionDocumentations; 66 | } 67 | 68 | static HashSet acceptableTypes = new HashSet() { 69 | typeof(float), 70 | typeof(string), 71 | typeof(bool), 72 | typeof(Range), 73 | typeof(void), 74 | typeof(object[]), 75 | typeof(SortedDictionary), 76 | }; 77 | 78 | static List CreateFunctionDefinitions (object pProgramTarget, Dictionary functionDocumentations, MethodInfo[] methodInfos) 79 | { 80 | List functionDefinitions = new List(); 81 | 82 | foreach (MethodInfo methodInfo in methodInfos) 83 | { 84 | if (!methodInfo.Name.StartsWith ("API_")) { 85 | continue; 86 | } 87 | 88 | MethodInfo lambdaMethodInfo = methodInfo; // "hard copy" because of c# lambda rules 89 | 90 | string shortname = lambdaMethodInfo.Name.Substring (4); 91 | 92 | List parameterTypes = new List (); 93 | List parameterNames = new List (); 94 | List parameterTypeNames = new List (); 95 | 96 | foreach (ParameterInfo parameterInfo in lambdaMethodInfo.GetParameters ()) { 97 | var t = ReturnValueConversions.SystemTypeToReturnValueType (parameterInfo.ParameterType); 98 | //Console.WriteLine("Registering parameter '" + parameterInfo.Name + "' (" + parameterInfo.ParameterType + ") with ReturnValueType " + t + " for function " + shortname); 99 | parameterNames.Add (parameterInfo.Name); 100 | parameterTypes.Add (t); 101 | parameterTypeNames.Add (t.ToString().ToLower()); 102 | } 103 | 104 | ExternalFunctionCreator.OnFunctionCall function = (sprakArguments => { 105 | 106 | ParameterInfo[] realParamInfo = lambdaMethodInfo.GetParameters (); 107 | 108 | if(sprakArguments.Count() != realParamInfo.Length) { 109 | throw new Error("Should call '" + shortname + "' with " + realParamInfo.Length + " argument" + (realParamInfo.Length == 1 ? "" : "s")); 110 | } 111 | 112 | int i = 0; 113 | foreach (object sprakArg in sprakArguments) { 114 | //Console.WriteLine(string.Format("Parameter {0} in function {1} is of type {2}", i, shortname, realParamInfo[i].ParameterType)); 115 | 116 | var realParamType = realParamInfo [i].ParameterType; 117 | 118 | if(sprakArg.GetType() == typeof(SortedDictionary)) { 119 | sprakArguments[i] = (sprakArg as SortedDictionary).Values.ToArray(); 120 | } 121 | 122 | if(sprakArg.GetType() == typeof(int)) { 123 | // YES, this is kind of a HACK (allowing definitions with int arguments, making them work like the were floats. Remove later! 124 | sprakArguments[i] = (float)sprakArg; 125 | realParamType = typeof(int); 126 | } 127 | 128 | if (acceptableTypes.Contains(realParamType)) { 129 | // OK 130 | } 131 | else { 132 | throw new Error("Can't deal with parameter " + i.ToString() + " of type " + realParamType + " in function " + shortname); 133 | } 134 | 135 | i++; 136 | } 137 | 138 | //Console.WriteLine("supplied parameter count" + parameters.Count + " neededParamter count " + lamdaMethodInfo.GetParameters().Length); 139 | 140 | object result = null; 141 | 142 | try { 143 | /* 144 | Console.WriteLine("Will call " + shortname + " with sprak arguments:"); 145 | int j = 0; 146 | foreach(var a in sprakArguments) { 147 | Console.WriteLine(" Argument " + (j++) + ": " + ReturnValueConversions.PrettyStringRepresenation(a) + " (" + a.GetType() + ")"); 148 | } 149 | */ 150 | result = lambdaMethodInfo.Invoke (pProgramTarget, sprakArguments.ToArray ()); 151 | } 152 | catch(System.Reflection.TargetInvocationException e) { 153 | //Console.WriteLine("Got an exception when calling the lambda: " + e.ToString()); 154 | //Console.WriteLine("The base exception: " + e.GetBaseException().ToString()); 155 | throw e.GetBaseException(); 156 | } 157 | 158 | // HACK 159 | if(lambdaMethodInfo.ReturnType == typeof(int)) { 160 | return (float)(int)result; 161 | } 162 | 163 | if(lambdaMethodInfo.ReturnType.IsSubclassOf(typeof(Array))) { 164 | var dictArray = new SortedDictionary(); 165 | int j = 0; 166 | foreach(var o in (Array)result) { 167 | //Console.WriteLine(" - " + o.ToString()); 168 | dictArray.Add(new KeyWrapper((float)j++), o); 169 | } 170 | //Console.WriteLine("Converted object[] to SortedDictionary when returning from " + shortname + ": " + ReturnValueConversions.PrettyStringRepresenation(dictArray)); 171 | return dictArray; 172 | } 173 | 174 | if(!acceptableTypes.Contains(lambdaMethodInfo.ReturnType)) { 175 | throw new Error("Function '" + shortname + "' can't return value of type " + lambdaMethodInfo.ReturnType.ToString()); 176 | } 177 | 178 | if (lambdaMethodInfo.ReturnType == typeof(void)) { 179 | //Console.WriteLine("Returning void from " + shortname); 180 | return VoidType.voidType; 181 | } 182 | else { 183 | //Console.WriteLine("Returning from " + shortname + ": " + ReturnValueConversions.PrettyStringRepresenation(result)); 184 | return result; 185 | } 186 | }); 187 | 188 | ReturnValueType returnValueType = ReturnValueConversions.SystemTypeToReturnValueType (lambdaMethodInfo.ReturnType); 189 | 190 | FunctionDocumentation doc; 191 | 192 | if (functionDocumentations.ContainsKey (shortname)) { 193 | doc = functionDocumentations [shortname]; 194 | } else { 195 | doc = FunctionDocumentation.Default (); 196 | } 197 | 198 | functionDefinitions.Add (new FunctionDefinition ( 199 | returnValueType.ToString (), 200 | shortname, 201 | parameterTypeNames.ToArray (), 202 | parameterNames.ToArray (), 203 | function, // The lambda 204 | doc)); 205 | } 206 | 207 | return functionDefinitions; 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/Errors/ErrorHandler_TEST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using System.IO; 4 | using System.Collections.Generic; 5 | 6 | namespace ProgrammingLanguageNr1 7 | { 8 | [TestFixture()] 9 | public class ErrorHandler_TEST 10 | { 11 | [Test()] 12 | public void BasicErrorHandlerUsage () 13 | { 14 | ErrorHandler errorHandler = new ErrorHandler(); 15 | errorHandler.errorOccured("Test error 1.", Error.ErrorType.UNDEFINED); 16 | errorHandler.errorOccured("Test error 2.", Error.ErrorType.SYNTAX, 10, 20); 17 | 18 | Assert.AreEqual(2, errorHandler.getErrors().Count); 19 | } 20 | 21 | [Test()] 22 | public void UnrecognizedChar () 23 | { 24 | TextReader reader = File.OpenText("code17.txt"); 25 | ErrorHandler errorHandler = new ErrorHandler(); 26 | Tokenizer tokenizer = new Tokenizer(errorHandler, true); 27 | tokenizer.process(File.OpenText("code17.txt")); 28 | List errors = errorHandler.getErrors(); 29 | Assert.AreEqual(3, errors.Count); 30 | } 31 | 32 | [Test()] 33 | public void TooManyTokensInStatements () 34 | { 35 | ErrorHandler errorHandler = new ErrorHandler(); 36 | Tokenizer tokenizer = new Tokenizer(errorHandler, true); 37 | List tokens = tokenizer.process(File.OpenText("code18.txt")); 38 | Parser parser = new Parser(tokens, errorHandler); 39 | parser.process(); 40 | errorHandler.printErrorsToConsole(); 41 | 42 | Assert.AreEqual(3, errorHandler.getErrors().Count); 43 | } 44 | 45 | [Test()] 46 | public void FunctionCallWithMissedParanthesis () 47 | { 48 | TextReader programString = new StringReader("f("); 49 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 50 | program.getErrorHandler().printErrorsToConsole(); 51 | 52 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 53 | Assert.AreEqual("Something is wrong with the argument list", 54 | program.getErrorHandler().getErrors()[0].getMessage()); 55 | } 56 | 57 | [Test()] 58 | public void FunctionCallWithMissedParanthesis2 () 59 | { 60 | TextReader programString = new StringReader("f(a"); 61 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 62 | program.getErrorHandler().printErrorsToConsole(); 63 | 64 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 65 | Assert.AreEqual("Ending parenthesis is missing in function call", 66 | program.getErrorHandler().getErrors()[0].getMessage()); 67 | } 68 | 69 | [Test()] 70 | public void FunctionCallWithMissedCommaInArgumentList () 71 | { 72 | TextReader programString = new StringReader("f(a b)"); 73 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 74 | program.getErrorHandler().printErrorsToConsole(); 75 | 76 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 77 | Assert.AreEqual("Comma is missing in argument list", 78 | program.getErrorHandler().getErrors()[0].getMessage()); 79 | } 80 | 81 | [Test()] 82 | public void IfStatementWithMissedParenthesis () 83 | { 84 | TextReader programString = new StringReader("if(a > b { }"); 85 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 86 | program.getErrorHandler().printErrorsToConsole(); 87 | 88 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 89 | Assert.AreEqual("If statement isn't complete", 90 | program.getErrorHandler().getErrors()[0].getMessage()); 91 | } 92 | 93 | [Test()] 94 | public void IfStatementWithStrangeConditional () 95 | { 96 | TextReader programString = new StringReader("if(a, b) { }"); 97 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 98 | program.getErrorHandler().printErrorsToConsole(); 99 | 100 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 101 | Assert.AreEqual("If statement isn't complete", 102 | program.getErrorHandler().getErrors()[0].getMessage()); 103 | } 104 | 105 | [Test()] 106 | public void IfStatementWithMissingEndBlock () 107 | { 108 | TextReader programString = new StringReader("if(a == b) { print(42) "); 109 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 110 | program.getErrorHandler().printErrorsToConsole(); 111 | 112 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 113 | Assert.AreEqual("If statement isn't complete", 114 | program.getErrorHandler().getErrors()[0].getMessage()); 115 | } 116 | 117 | //[Test()] 118 | //public void FunctionWithNoExpressionInReturn () 119 | //{ 120 | // TextReader programString = File.OpenText("code31.txt"); 121 | // SprakProgram program = new SprakProgram(programString); 122 | // program.getErrorHandler().printErrorsToConsole(); 123 | 124 | // Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 125 | // Assert.AreEqual("No expression in return statement", 126 | // program.getErrorHandler().getErrors()[0].getMessage()); 127 | //} 128 | 129 | [Test()] 130 | public void AssignmentWithNoExpression () 131 | { 132 | TextReader programString = File.OpenText("code32.txt"); 133 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 134 | program.getErrorHandler().printErrorsToConsole(); 135 | 136 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 137 | Assert.AreEqual("Missing expression in assignment", 138 | program.getErrorHandler().getErrors()[0].getMessage()); 139 | } 140 | 141 | [Test()] 142 | public void AssignmentWithNoExpression2 () 143 | { 144 | TextReader programString = File.OpenText("code33.txt"); 145 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 146 | program.getErrorHandler().printErrorsToConsole(); 147 | 148 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 149 | Assert.AreEqual("Missing expression in assignment", 150 | program.getErrorHandler().getErrors()[0].getMessage()); 151 | } 152 | 153 | [Test()] 154 | public void UsingReservedWordAsVariableName () 155 | { 156 | TextReader programString = File.OpenText("code34.txt"); 157 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 158 | program.getErrorHandler().printErrorsToConsole(); 159 | 160 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 161 | Assert.AreEqual("Can't figure out statement type of token BUILT_IN_TYPE with string float", 162 | program.getErrorHandler().getErrors()[0].getMessage()); 163 | } 164 | 165 | 166 | [Test()] 167 | public void CallingUndefinedFunction () 168 | { 169 | TextReader programString = new StringReader("f()"); 170 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 171 | //program.getErrorHandler().printErrorsToConsole(); 172 | 173 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 174 | Assert.AreEqual("Can't find function with name f", 175 | program.getErrorHandler().getErrors()[0].getMessage()); 176 | } 177 | 178 | [Test()] 179 | public void WrongNumberOfArgumentsToFunction () 180 | { 181 | TextReader programString = File.OpenText("code30.txt"); 182 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 183 | program.run(); 184 | //program.getErrorHandler().printErrorsToConsole(); 185 | 186 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 187 | Assert.AreEqual("Wrong number of arguments to function", 188 | program.getErrorHandler().getErrors()[0].getMessage()); 189 | } 190 | 191 | [Test()] 192 | public void FunctionDefinitionWithoutBody () 193 | { 194 | TextReader programString = File.OpenText("code37.txt"); 195 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 196 | program.run(); 197 | program.getErrorHandler().printErrorsToConsole(); 198 | 199 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 200 | Assert.AreEqual("Missing curly bracket in beginning of function definition", 201 | program.getErrorHandler().getErrors()[0].getMessage()); 202 | } 203 | 204 | [Test()] 205 | public void FunctionDefinitionWithoutEndingBracket () 206 | { 207 | TextReader programString = File.OpenText("code38.txt"); 208 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 209 | program.run(); 210 | program.getErrorHandler().printErrorsToConsole(); 211 | 212 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 213 | Assert.AreEqual("Trying to define a function inside a function (are you missing a curly bracket?)", 214 | program.getErrorHandler().getErrors()[0].getMessage()); 215 | } 216 | 217 | [Test()] 218 | public void DefiningVariableWithUnknownType () 219 | { 220 | TextReader programString = new StringReader("superinteger a"); 221 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 222 | //program.getErrorHandler().printErrorsToConsole(); 223 | 224 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 225 | Assert.AreEqual("Can't find type with name superinteger", 226 | program.getErrorHandler().getErrors()[0].getMessage()); 227 | } 228 | 229 | [Test()] 230 | public void DeclareVariableTwice () 231 | { 232 | TextReader programString = File.OpenText("code39.txt"); 233 | DefaultSprakRunner program = new DefaultSprakRunner(programString); 234 | //program.getErrorHandler().printErrorsToConsole(); 235 | 236 | Assert.AreEqual(1, program.getErrorHandler().getErrors().Count); 237 | Assert.AreEqual("Trying to redefine symbol with name a", 238 | program.getErrorHandler().getErrors()[0].getMessage()); 239 | } 240 | } 241 | } 242 | 243 | -------------------------------------------------------------------------------- /Sprak_Tests/tests/Parser_TEST.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using System.Text; 4 | using System.IO; 5 | using System.Collections.Generic; 6 | 7 | namespace ProgrammingLanguageNr1.tests 8 | { 9 | [TestFixture()] 10 | public class Parser_TEST 11 | { 12 | static ErrorHandler s_errorHandler = new ErrorHandler(); 13 | 14 | [Test()] 15 | public void ParseCode1 () 16 | { 17 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 18 | List tokens = tokenizer.process(File.OpenText("code1.txt")); 19 | Parser parser = new Parser(tokens, s_errorHandler); 20 | parser.process(); 21 | } 22 | 23 | [Test()] 24 | public void ParseCode2 () 25 | { 26 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 27 | List tokens = tokenizer.process(File.OpenText("code2.txt")); 28 | Parser parser = new Parser(tokens, s_errorHandler); 29 | parser.process(); 30 | } 31 | 32 | [Test()] 33 | public void ParseCode3 () 34 | { 35 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 36 | List tokens = tokenizer.process(File.OpenText("code3.txt")); 37 | Parser parser = new Parser(tokens, s_errorHandler); 38 | parser.process(); 39 | } 40 | 41 | [Test()] 42 | public void Lookahead () 43 | { 44 | List tokens = new List(); 45 | tokens.Add(new Token(Token.TokenType.NAME, "a")); 46 | tokens.Add(new Token(Token.TokenType.NUMBER, "45")); 47 | tokens.Add(new Token(Token.TokenType.OPERATOR, "+")); 48 | tokens.Add(new Token(Token.TokenType.NEW_LINE, "")); 49 | tokens.Add(new Token(Token.TokenType.EOF, "")); 50 | 51 | Parser parser = new Parser(tokens, s_errorHandler); 52 | Assert.AreEqual(Token.TokenType.NAME, parser.lookAhead(1).getTokenType()); 53 | Assert.AreEqual(Token.TokenType.NUMBER, parser.lookAhead(2).getTokenType()); 54 | Assert.AreEqual(Token.TokenType.OPERATOR, parser.lookAhead(3).getTokenType()); 55 | 56 | parser.consumeCurrentToken(); 57 | parser.consumeCurrentToken(); 58 | 59 | Assert.AreEqual(Token.TokenType.OPERATOR, parser.lookAheadType(1)); 60 | Assert.AreEqual(Token.TokenType.NEW_LINE, parser.lookAheadType(2)); 61 | Assert.AreEqual(Token.TokenType.EOF, parser.lookAheadType(3)); 62 | 63 | parser.consumeCurrentToken(); 64 | parser.consumeCurrentToken(); 65 | 66 | Assert.AreEqual(Token.TokenType.EOF, parser.lookAhead(1).getTokenType()); 67 | } 68 | 69 | [Test()] 70 | public void ParseSimpleExpression () 71 | { 72 | List tokens = new List(); 73 | tokens.Add(new Token(Token.TokenType.NAME, "a")); 74 | tokens.Add(new Token(Token.TokenType.OPERATOR, "+")); 75 | tokens.Add(new Token(Token.TokenType.NAME, "b")); 76 | 77 | ErrorHandler errorHandler = new ErrorHandler(); 78 | Parser parser = new Parser(tokens, errorHandler); 79 | parser.process(); 80 | 81 | Assert.AreEqual(0, errorHandler.getErrors().Count); 82 | } 83 | 84 | [Test()] 85 | public void ParseAssignment () 86 | { 87 | List tokens = new List(); 88 | tokens.Add(new Token(Token.TokenType.NAME, "variable")); 89 | tokens.Add(new Token(Token.TokenType.ASSIGNMENT, "=")); 90 | tokens.Add(new Token(Token.TokenType.NUMBER, "42")); 91 | 92 | ErrorHandler errorHandler = new ErrorHandler(); 93 | Parser parser = new Parser(tokens, errorHandler); 94 | parser.process(); 95 | 96 | Assert.AreEqual(0, errorHandler.getErrors().Count); 97 | } 98 | 99 | [Test()] 100 | public void ParseSingleName () 101 | { 102 | List tokens = new List(); 103 | tokens.Add(new Token(Token.TokenType.NAME, "erik")); 104 | 105 | ErrorHandler errorHandler = new ErrorHandler(); 106 | Parser parser = new Parser(tokens, errorHandler); 107 | parser.process(); 108 | 109 | Assert.AreEqual(0, errorHandler.getErrors().Count); 110 | } 111 | 112 | [Test()] 113 | public void ParseLongerExpression () 114 | { 115 | List tokens = new List(); 116 | 117 | tokens.Add(new Token(Token.TokenType.NUMBER, "2")); 118 | tokens.Add(new Token(Token.TokenType.OPERATOR, "*")); 119 | tokens.Add(new Token(Token.TokenType.NUMBER, "3")); 120 | tokens.Add(new Token(Token.TokenType.OPERATOR, "+")); 121 | tokens.Add(new Token(Token.TokenType.NUMBER, "4")); 122 | tokens.Add(new Token(Token.TokenType.OPERATOR, "*")); 123 | tokens.Add(new Token(Token.TokenType.NUMBER, "5")); 124 | 125 | ErrorHandler errorHandler = new ErrorHandler(); 126 | Parser parser = new Parser(tokens, errorHandler); 127 | parser.process(); 128 | 129 | Assert.AreEqual(0, errorHandler.getErrors().Count); 130 | } 131 | 132 | [Test()] 133 | public void ParseFunctionCallWithParameters () 134 | { 135 | List tokens = new List(); 136 | 137 | tokens.Add(new Token(Token.TokenType.NAME, "foo")); 138 | tokens.Add(new Token(Token.TokenType.PARANTHESIS_LEFT, "(")); 139 | tokens.Add(new Token(Token.TokenType.NAME, "a")); 140 | tokens.Add(new Token(Token.TokenType.COMMA, ",")); 141 | tokens.Add(new Token(Token.TokenType.NAME, "bar")); 142 | tokens.Add(new Token(Token.TokenType.PARANTHESIS_LEFT, "(")); 143 | tokens.Add(new Token(Token.TokenType.PARANTHESIS_RIGHT, ")")); 144 | tokens.Add(new Token(Token.TokenType.COMMA, ",")); 145 | tokens.Add(new Token(Token.TokenType.NUMBER, "400")); 146 | tokens.Add(new Token(Token.TokenType.PARANTHESIS_RIGHT, ")")); 147 | 148 | ErrorHandler errorHandler = new ErrorHandler(); 149 | Parser parser = new Parser(tokens, errorHandler); 150 | parser.process(); 151 | 152 | Assert.AreEqual(0, errorHandler.getErrors().Count); 153 | } 154 | 155 | [Test()] 156 | public void ParseIfElseBlock () 157 | { 158 | List tokens = new List(); 159 | 160 | tokens.Add(new Token(Token.TokenType.IF, "if")); 161 | tokens.Add(new Token(Token.TokenType.PARANTHESIS_LEFT, "(")); 162 | tokens.Add(new Token(Token.TokenType.NAME, "m_hasGotCandy")); 163 | tokens.Add(new Token(Token.TokenType.PARANTHESIS_RIGHT, ")")); 164 | tokens.Add(new Token(Token.TokenType.NEW_LINE, "\n")); 165 | tokens.Add(new Token(Token.TokenType.NAME, "boringFunction")); 166 | tokens.Add(new Token(Token.TokenType.PARANTHESIS_LEFT, "(")); 167 | tokens.Add(new Token(Token.TokenType.PARANTHESIS_RIGHT, ")")); 168 | tokens.Add(new Token(Token.TokenType.NEW_LINE, "\n")); 169 | tokens.Add(new Token(Token.TokenType.BLOCK_END, "end")); 170 | tokens.Add(new Token(Token.TokenType.ELSE, "else")); 171 | tokens.Add(new Token(Token.TokenType.NEW_LINE, "\n")); 172 | tokens.Add(new Token(Token.TokenType.BLOCK_END, "end")); 173 | 174 | ErrorHandler errorHandler = new ErrorHandler(); 175 | Parser parser = new Parser(tokens, errorHandler); 176 | parser.process(); 177 | 178 | Assert.AreEqual(0, errorHandler.getErrors().Count); 179 | } 180 | 181 | [Test()] 182 | public void ParseFunctionDeclaration () 183 | { 184 | List tokens = new List(); 185 | 186 | tokens.Add(new Token(Token.TokenType.BUILT_IN_TYPE_NAME, "float")); 187 | tokens.Add(new Token(Token.TokenType.NAME, "foo")); 188 | tokens.Add(new Token(Token.TokenType.PARANTHESIS_LEFT, "(")); 189 | tokens.Add(new Token(Token.TokenType.PARANTHESIS_RIGHT, ")")); 190 | tokens.Add(new Token(Token.TokenType.BLOCK_END, "end")); 191 | 192 | ErrorHandler errorHandler = new ErrorHandler(); 193 | Parser parser = new Parser(tokens, errorHandler); 194 | parser.process(); 195 | 196 | Console.WriteLine("Tree: " + parser.getAST().getTreeAsString()); 197 | errorHandler.printErrorsToConsole(); 198 | 199 | Assert.AreEqual(0, errorHandler.getErrors().Count); 200 | } 201 | 202 | [Test()] 203 | public void ParseSomeExpressionsWithFunctions () 204 | { 205 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 206 | List tokens = tokenizer.process(File.OpenText("code15.txt")); 207 | 208 | ErrorHandler errorHandler = new ErrorHandler(); 209 | Parser parser = new Parser(tokens, errorHandler); 210 | parser.process(); 211 | 212 | //Console.WriteLine("Tree: " + parser.getAST().getTreeAsString()); 213 | 214 | Assert.AreEqual(0, errorHandler.getErrors().Count); 215 | } 216 | 217 | 218 | 219 | 220 | 221 | ////////////// AST-CREATION /////////////// 222 | 223 | [Test()] 224 | public void CreatingSimpleTree() 225 | { 226 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 227 | List tokens = tokenizer.process(File.OpenText("code4.txt")); 228 | 229 | Parser parser = new Parser(tokens, s_errorHandler); 230 | parser.process(); 231 | 232 | //Console.WriteLine("Tree: " + parser.getAST().toStringTree()); 233 | ASTPainter p = new ASTPainter(); 234 | p.PaintAST(parser.getAST()); 235 | 236 | AST root = parser.getAST(); 237 | Assert.AreEqual(Token.TokenType.PROGRAM_ROOT, root.getTokenType()); 238 | 239 | AST statementList = root.getChild(0); 240 | Assert.AreEqual(Token.TokenType.STATEMENT_LIST, statementList.getTokenType()); 241 | 242 | AST multiplicationTree = statementList.getChild(1); 243 | Assert.AreEqual(Token.TokenType.OPERATOR, multiplicationTree.getTokenType()); 244 | 245 | AST operand1 = multiplicationTree.getChild(0); 246 | AST operand2 = multiplicationTree.getChild(1); 247 | Assert.AreEqual("a", operand1.getTokenString()); 248 | Assert.AreEqual("b", operand2.getTokenString()); 249 | } 250 | 251 | [Test()] 252 | public void OperationOrder() 253 | { 254 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 255 | List tokens = tokenizer.process(File.OpenText("code6.txt")); 256 | 257 | Parser parser = new Parser(tokens, s_errorHandler); 258 | parser.process(); 259 | 260 | //Console.WriteLine("Tree: " + parser.getAST().toStringTree()); 261 | 262 | Assert.AreEqual("( (+ (* a b) (+ (* c d) e)))", 263 | parser.getAST().getChild(0).getTreeAsString()); 264 | } 265 | 266 | [Test()] 267 | public void ParenthesisBasics() 268 | { 269 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 270 | List tokens = tokenizer.process(File.OpenText("code7.txt")); 271 | 272 | Parser parser = new Parser(tokens, s_errorHandler); 273 | parser.process(); 274 | 275 | //Console.WriteLine("Tree: " + parser.getAST().toStringTree()); 276 | 277 | Assert.AreEqual("( (* a (/ (+ b c) d)))", parser.getAST().getChild(0).getTreeAsString()); 278 | } 279 | 280 | [Test()] 281 | public void ComplexExpressions() 282 | { 283 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 284 | List tokens = tokenizer.process(File.OpenText("code8.txt")); 285 | 286 | Parser parser = new Parser(tokens, s_errorHandler); 287 | parser.process(); 288 | 289 | //Console.WriteLine("Tree: " + parser.getAST().getTreeAsString()); 290 | } 291 | 292 | [Test()] 293 | public void Backtrack () 294 | { 295 | StringReader programString = new StringReader( 296 | "a b c d e f g h" 297 | ); 298 | 299 | Tokenizer tokenizer = new Tokenizer(s_errorHandler, true); 300 | List tokens = tokenizer.process(programString); 301 | 302 | tokens.ForEach (t => Console.WriteLine(t.getTokenType().ToString() + ", " + t.getTokenString())); 303 | 304 | Assert.AreEqual(9, tokens.Count); 305 | 306 | Parser parser = new Parser(tokens, s_errorHandler); 307 | 308 | Assert.AreEqual ("a", parser.lookAhead (1).getTokenString ()); 309 | parser.consumeCurrentToken (); 310 | Assert.AreEqual ("b", parser.lookAhead (1).getTokenString ()); 311 | parser.consumeCurrentToken (); 312 | parser.consumeCurrentToken (); 313 | parser.consumeCurrentToken (); 314 | Assert.AreEqual ("e", parser.lookAhead (1).getTokenString ()); 315 | var savePoint = parser.lookAhead(1); 316 | Assert.AreEqual ("e", savePoint.getTokenString()); 317 | parser.consumeCurrentToken (); 318 | parser.consumeCurrentToken (); 319 | Assert.AreEqual ("g", parser.lookAhead (1).getTokenString ()); 320 | parser.backtrackToToken (savePoint); 321 | Assert.AreEqual ("e", parser.lookAhead (1).getTokenString ()); 322 | } 323 | } 324 | } 325 | 326 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/1. Tokenize/Tokenizer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Diagnostics; 6 | 7 | namespace ProgrammingLanguageNr1 8 | { 9 | public class Tokenizer 10 | { 11 | static char WINDOWS_LINE_ENDING_CRAP = (char)13; 12 | 13 | public Tokenizer(ErrorHandler errorHandler, bool stripOutComments) 14 | { 15 | m_errorHandler = errorHandler; 16 | m_stripOutComments = stripOutComments; 17 | } 18 | 19 | public List process(TextReader textReader) { 20 | Debug.Assert(textReader != null); 21 | 22 | m_tokens = new List(); 23 | m_textReader = textReader; 24 | m_endOfFile = false; 25 | 26 | readNextChar(); 27 | m_currentLine = 1; 28 | m_currentPosition = 0; 29 | m_currentTokenStartPosition = 0; 30 | 31 | Token t; 32 | 33 | do { 34 | t = readNextToken(); 35 | t.LineNr = m_currentLine; 36 | t.LinePosition = m_currentTokenStartPosition; 37 | m_currentTokenStartPosition = m_currentPosition; 38 | 39 | m_tokens.Add(t); 40 | 41 | //Console.WriteLine(t.LineNr + ": " + t.getTokenType().ToString() + " " + t.getTokenString()); 42 | 43 | } while(t.getTokenType() != Token.TokenType.EOF); 44 | 45 | m_textReader.Close(); 46 | m_textReader.Dispose(); 47 | 48 | return m_tokens; 49 | } 50 | 51 | private Token readNextToken() { 52 | 53 | while (!m_endOfFile) { 54 | 55 | switch(m_currentChar) 56 | { 57 | case '\0': 58 | m_endOfFile = true; 59 | continue; 60 | 61 | case ' ': case '\t': case ';': 62 | readNextChar(); 63 | continue; 64 | 65 | case '#': 66 | if (m_stripOutComments) 67 | { 68 | stripComment(); 69 | continue; 70 | } 71 | else 72 | { 73 | return COMMENT(); 74 | } 75 | 76 | case '\n': 77 | return NEW_LINE(); 78 | 79 | case '+': case '-': case '*': case '/': case '<': 80 | case '>': case '=': case '!': case '&': case '|': 81 | return OPERATOR(); 82 | 83 | case '(': 84 | return PARANTHESIS_LEFT(); 85 | 86 | case ')': 87 | return PARANTHESIS_RIGHT(); 88 | 89 | case '[': 90 | return BRACKET_LEFT(); 91 | 92 | case ']': 93 | return BRACKET_RIGHT(); 94 | 95 | case '\"': 96 | return QUOTED_STRING(true); 97 | 98 | case '\'': 99 | return QUOTED_STRING(false); 100 | 101 | case ',': 102 | return COMMA(); 103 | 104 | case '.': 105 | return DOT(); 106 | 107 | default: 108 | if( isLETTER() ) { 109 | return NAME(); 110 | } 111 | else if ( isDIGIT() ) { 112 | return NUMBER(false); 113 | } 114 | else if(m_currentChar == WINDOWS_LINE_ENDING_CRAP) { 115 | return NEW_LINE(); 116 | } 117 | else 118 | { 119 | m_errorHandler.errorOccured( 120 | "Can't understand this character: \'" + 121 | m_currentChar + 122 | "\' (int code " + (int)m_currentChar + ")", 123 | Error.ErrorType.SYNTAX, 124 | m_currentLine, 125 | m_currentPosition); 126 | // Try to recover: 127 | readNextChar(); 128 | continue; 129 | } 130 | } 131 | 132 | } 133 | 134 | return new Token(Token.TokenType.EOF, ""); 135 | } 136 | 137 | private void stripComment() 138 | { 139 | while (m_currentChar != '\n' && m_currentChar != '\0') 140 | { 141 | readNextChar(); 142 | } 143 | return; 144 | } 145 | 146 | private Token COMMENT() { 147 | StringBuilder tokenString = new StringBuilder(); 148 | 149 | while(m_currentChar != '\n' && m_currentChar != '\0') { 150 | tokenString.Append(m_currentChar); 151 | readNextChar(); 152 | } 153 | return new Token(Token.TokenType.COMMENT, tokenString.ToString()); 154 | } 155 | 156 | private Token COMMA() { 157 | readNextChar(); 158 | return new Token(Token.TokenType.COMMA, ","); 159 | } 160 | 161 | private Token DOT() { 162 | readNextChar(); 163 | return new Token(Token.TokenType.DOT, "."); 164 | } 165 | 166 | private Token NOT() { 167 | return new Token(Token.TokenType.NOT, "!"); 168 | } 169 | 170 | private Token NEW_LINE() { 171 | while(m_currentChar == '\n' || m_currentChar == WINDOWS_LINE_ENDING_CRAP) { // make several new-lines into a single one 172 | m_currentLine++; 173 | m_currentPosition = 0; 174 | readNextChar(); 175 | } 176 | return new Token(Token.TokenType.NEW_LINE, ""); 177 | } 178 | 179 | private Token OPERATOR () 180 | { 181 | StringBuilder tokenString = new StringBuilder (); 182 | tokenString.Append (m_currentChar); 183 | 184 | char firstChar = m_currentChar; 185 | readNextChar (); 186 | 187 | if (firstChar == '-' && isDIGIT()) { 188 | // Negative number! 189 | return NUMBER(true); 190 | } 191 | else if ( (firstChar == '<' || firstChar == '>') && m_currentChar == '=') { 192 | tokenString.Append ('='); 193 | readNextChar(); 194 | } 195 | else if ( firstChar == '=') { 196 | if( m_currentChar == '=' ) { 197 | tokenString.Append ('='); 198 | readNextChar(); 199 | } else { 200 | return ASSIGNMENT(); 201 | } 202 | } 203 | else if ( firstChar == '!' && m_currentChar == '=') { 204 | tokenString.Append ('='); 205 | readNextChar(); 206 | } 207 | else if ( firstChar == '!') { 208 | return NOT(); 209 | } 210 | else if ( firstChar == '&' && m_currentChar == '&') { 211 | tokenString.Append ('&'); 212 | readNextChar(); 213 | } 214 | else if ( firstChar == '|' && m_currentChar == '|') { 215 | tokenString.Append ('|'); 216 | readNextChar(); 217 | } 218 | else if( firstChar == '+' && m_currentChar == '+') { 219 | tokenString.Append('+'); 220 | readNextChar(); 221 | } 222 | else if( firstChar == '-' && m_currentChar == '-') { 223 | tokenString.Append('-'); 224 | readNextChar(); 225 | } 226 | else if( firstChar == '+' && m_currentChar == '=') { 227 | tokenString.Append('='); 228 | readNextChar(); 229 | } 230 | else if( firstChar == '*' && m_currentChar == '=') { 231 | tokenString.Append('='); 232 | readNextChar(); 233 | } 234 | else if( firstChar == '-' && m_currentChar == '=') { 235 | tokenString.Append('='); 236 | readNextChar(); 237 | } 238 | else if( firstChar == '/' && m_currentChar == '=') { 239 | tokenString.Append('='); 240 | readNextChar(); 241 | } 242 | 243 | return new Token(Token.TokenType.OPERATOR, tokenString.ToString()); 244 | } 245 | 246 | private Token PARANTHESIS_LEFT() { 247 | readNextChar(); 248 | return new Token(Token.TokenType.PARANTHESIS_LEFT, "("); 249 | } 250 | 251 | private Token PARANTHESIS_RIGHT() { 252 | readNextChar(); 253 | return new Token(Token.TokenType.PARANTHESIS_RIGHT, ")"); 254 | } 255 | 256 | private Token BRACKET_LEFT() { 257 | readNextChar(); 258 | return new Token(Token.TokenType.BRACKET_LEFT, "["); 259 | } 260 | 261 | private Token BRACKET_RIGHT() { 262 | readNextChar(); 263 | return new Token(Token.TokenType.BRACKET_RIGHT, "]"); 264 | } 265 | 266 | private Token QUOTED_STRING(bool pDoubleQuoted) { 267 | var terminatingQuoteChar = pDoubleQuoted ? '\"' : '\''; 268 | 269 | StringBuilder tokenString = new StringBuilder(); 270 | readNextChar(); 271 | while (m_currentChar != terminatingQuoteChar && m_currentChar != '\n' && m_currentChar != '\0') 272 | { 273 | tokenString.Append(m_currentChar); 274 | readNextChar(); 275 | } 276 | 277 | readNextChar(); 278 | return new Token(Token.TokenType.QUOTED_STRING, tokenString.ToString()); 279 | } 280 | 281 | private Token ASSIGNMENT() { 282 | return new Token(Token.TokenType.ASSIGNMENT, "="); 283 | } 284 | 285 | private Token NAME() { 286 | StringBuilder tokenString = new StringBuilder(); 287 | do { 288 | tokenString.Append(m_currentChar); 289 | readNextChar(); 290 | } while( isLETTER() || isDIGIT() ); 291 | 292 | Token.TokenType tokenType = Token.TokenType.NAME; 293 | string ts = tokenString.ToString (); 294 | string tsLowercase = ts.ToLower(); 295 | 296 | // Keywords 297 | if(tsLowercase == "if") 298 | { 299 | tokenType = Token.TokenType.IF; 300 | } 301 | else if(tsLowercase == "else") 302 | { 303 | tokenType = Token.TokenType.ELSE; 304 | } 305 | else if(tsLowercase == "return") 306 | { 307 | tokenType = Token.TokenType.RETURN; 308 | } 309 | else if (tsLowercase == "void") 310 | { 311 | tokenType = Token.TokenType.BUILT_IN_TYPE_NAME; 312 | } 313 | else if (tsLowercase == "number") 314 | { 315 | tokenType = Token.TokenType.BUILT_IN_TYPE_NAME; 316 | } 317 | else if (tsLowercase == "string") 318 | { 319 | tokenType = Token.TokenType.BUILT_IN_TYPE_NAME; 320 | } 321 | else if (tsLowercase == "bool") 322 | { 323 | tokenType = Token.TokenType.BUILT_IN_TYPE_NAME; 324 | } 325 | else if (tsLowercase == "array") 326 | { 327 | tokenType = Token.TokenType.BUILT_IN_TYPE_NAME; 328 | } 329 | else if (tsLowercase == "var") 330 | { 331 | tokenType = Token.TokenType.BUILT_IN_TYPE_NAME; 332 | } 333 | else if (tsLowercase == "loop") 334 | { 335 | tokenType = Token.TokenType.LOOP; 336 | } 337 | else if (tsLowercase == "in") 338 | { 339 | tokenType = Token.TokenType.IN; 340 | } 341 | else if (ts == "break") // Break is reserved 342 | { 343 | tokenType = Token.TokenType.BREAK; 344 | } 345 | else if (tsLowercase == "from") 346 | { 347 | tokenType = Token.TokenType.FROM; 348 | } 349 | else if (tsLowercase == "to") 350 | { 351 | tokenType = Token.TokenType.TO; 352 | } 353 | else if (tsLowercase == "end") 354 | { 355 | tokenType = Token.TokenType.BLOCK_END; 356 | } 357 | else if (tsLowercase == "and") 358 | { 359 | tokenType = Token.TokenType.OPERATOR; 360 | ts = "&&"; 361 | } 362 | else if (tsLowercase == "or") 363 | { 364 | tokenType = Token.TokenType.OPERATOR; 365 | ts = "||"; 366 | } 367 | else if (tsLowercase == "true" || tsLowercase == "false") 368 | { 369 | tokenType = Token.TokenType.BOOLEAN_VALUE; 370 | } 371 | 372 | return new Token(tokenType, ts); 373 | } 374 | 375 | private Token NUMBER(bool negative) { 376 | StringBuilder tokenString = new StringBuilder(); 377 | if(negative) { tokenString.Append("-"); } 378 | bool period = false; 379 | do { 380 | if (m_currentChar == '.' && !period) { 381 | tokenString.Append("."); 382 | period = true; 383 | readNextChar(); 384 | } else if (m_currentChar == '.') { 385 | m_errorHandler.errorOccured("Can't have several period signs in a number!", Error.ErrorType.SYNTAX, m_currentLine, m_currentPosition); 386 | readNextChar(); 387 | break; 388 | } 389 | tokenString.Append(m_currentChar); 390 | readNextChar(); 391 | } while( isDIGIT() || m_currentChar == '.' ); 392 | 393 | return new Token(Token.TokenType.NUMBER, tokenString.ToString()); 394 | } 395 | 396 | private bool isLETTER() { 397 | 398 | foreach(char letter in s_letters) { 399 | if(m_currentChar == letter) return true; 400 | } 401 | return false; 402 | } 403 | 404 | private bool isDIGIT() { 405 | 406 | foreach(char digit in s_digits) { 407 | if(m_currentChar == digit) return true; 408 | } 409 | return false; 410 | } 411 | 412 | void readNextChar() { 413 | 414 | int c = m_textReader.Read(); 415 | 416 | if (c > 0) { 417 | m_currentChar = (char)c; 418 | m_currentPosition++; 419 | } 420 | else { 421 | m_currentChar = '\0'; 422 | m_endOfFile = true; 423 | } 424 | } 425 | 426 | List m_tokens; 427 | TextReader m_textReader; 428 | 429 | bool m_endOfFile; 430 | char m_currentChar; 431 | int m_currentLine; 432 | int m_currentPosition; 433 | int m_currentTokenStartPosition; 434 | bool m_stripOutComments; 435 | 436 | static string s_letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_@!?"; 437 | static string s_digits = "1234567890"; 438 | 439 | ErrorHandler m_errorHandler; 440 | } 441 | } 442 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/5. Run/Interpreter.cs: -------------------------------------------------------------------------------- 1 | // #define WRITE_DEBUG_INFO 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using NUnit.Framework; 6 | 7 | namespace ProgrammingLanguageNr1 8 | { 9 | public class Interpreter 10 | { 11 | public Interpreter (AST ast, Scope globalScope, ErrorHandler errorHandler, ExternalFunctionCreator externalFunctionCreator) 12 | { 13 | m_ast = ast; 14 | m_errorHandler = errorHandler; 15 | m_globalScope = globalScope; 16 | m_currentScope = m_globalScope; 17 | m_externalFunctionCreator = externalFunctionCreator; 18 | } 19 | 20 | public void run() 21 | { 22 | m_globalMemorySpace = new MemorySpace("globals"); 23 | m_currentMemorySpace = m_globalMemorySpace; 24 | 25 | execute(m_ast); 26 | } 27 | 28 | private ReturnValue execute(AST tree) { 29 | 30 | Token.TokenType tokenType = tree.getToken().getTokenType(); 31 | ReturnValue returnValue = null; 32 | 33 | if (tokenType == Token.TokenType.FUNC_DECLARATION) 34 | { 35 | return new ReturnValue(); 36 | } 37 | 38 | #if WRITE_DEBUG_INFO 39 | Console.WriteLine("Executing " + tree.getTokenType() + " " + tree.getTokenString()); 40 | #endif 41 | 42 | if (tokenType == Token.TokenType.STATEMENT_LIST) 43 | { 44 | executeAllChildNodes(tree); 45 | } 46 | else if (tokenType == Token.TokenType.FUNCTION_CALL) { 47 | returnValue = functionCall(tree); 48 | } 49 | else if (tokenType == Token.TokenType.NAME) { 50 | returnValue = name(tree); 51 | } 52 | else if (tokenType == Token.TokenType.NUMBER) { 53 | returnValue = number(tree); 54 | } 55 | else if (tokenType == Token.TokenType.OPERATOR) { 56 | returnValue = operation(tree); 57 | } 58 | else if (tokenType == Token.TokenType.QUOTED_STRING) { 59 | returnValue = quotedString(tree); 60 | } 61 | else if (tokenType == Token.TokenType.IF) { 62 | ifThenElse(tree); 63 | } 64 | else if (tokenType == Token.TokenType.VAR_DECLARATION) { 65 | varDeclaration(tree); 66 | } 67 | else if (tokenType == Token.TokenType.ASSIGNMENT) { 68 | assignment(tree); 69 | } 70 | else if (tokenType == Token.TokenType.RETURN) { 71 | returnStatement(tree); 72 | } 73 | else { 74 | throw new NotImplementedException("The interpreter hasn't got support for token type " + tokenType + " yet!"); 75 | } 76 | return returnValue; 77 | } 78 | 79 | private void executeAllChildNodes(AST tree) { 80 | if(tree.getChildren() == null) { return; } 81 | foreach (AST childTree in tree.getChildren()) { 82 | execute(childTree); 83 | } 84 | } 85 | 86 | private void varDeclaration(AST tree) { 87 | string typeName = tree.getChild(0).getTokenString(); 88 | ReturnValueType variableType = ReturnValue.getReturnValueTypeFromString(typeName); 89 | string variableName = tree.getChild(1).getTokenString(); 90 | 91 | switch(variableType) { 92 | case ReturnValueType.FLOAT: 93 | m_currentMemorySpace.setValue(variableName, new ReturnValue(0.0f)); 94 | break; 95 | case ReturnValueType.STRING: 96 | m_currentMemorySpace.setValue(variableName, new ReturnValue(0.0f)); 97 | break; 98 | default: 99 | throw new InvalidOperationException("Can't declare a variable of type " + typeName); 100 | } 101 | } 102 | 103 | private void assignment(AST tree) { 104 | string variableName = tree.getChild(0).getTokenString(); 105 | AST expression = tree.getChild(1); 106 | ReturnValue expressionValue = execute(expression); 107 | assignValue(variableName, expressionValue); 108 | } 109 | 110 | private void assignValue(string variableName, ReturnValue valueToAssign) { 111 | Assert.IsNotNull(m_currentScope); 112 | 113 | //Console.WriteLine("Current scope: " + m_currentScope.getName()); 114 | 115 | Symbol symbol = m_currentScope.resolve(variableName); 116 | if (symbol == null) { 117 | throw new InvalidOperationException("Can't resolve variable with name " + variableName); 118 | } 119 | 120 | ReturnValueType variableType = symbol.getReturnValueType(); 121 | 122 | switch(variableType) 123 | { 124 | case ReturnValueType.FLOAT: 125 | float floatValue = valueToAssign.FloatValue; 126 | ReturnValue floatVal = new ReturnValue(floatValue); 127 | m_currentMemorySpace.setValue(variableName, floatVal); 128 | break; 129 | 130 | case ReturnValueType.STRING: 131 | string stringValue = valueToAssign.StringValue; 132 | ReturnValue stringVal = new ReturnValue(stringValue); 133 | m_currentMemorySpace.setValue(variableName, stringVal); 134 | break; 135 | 136 | default: 137 | throw new InvalidOperationException("Can't assign to a variable of type + " + variableType); 138 | } 139 | } 140 | 141 | private ReturnValue functionCall(AST tree) { 142 | ReturnValue returnValue = null; 143 | 144 | if (m_externalFunctionCreator.externalFunctions.ContainsKey(tree.getTokenString())) 145 | { 146 | ExternalFunctionCreator.OnFunctionCall functionCall = m_externalFunctionCreator.externalFunctions[tree.getTokenString()]; 147 | if (functionCall != null) 148 | { 149 | ReturnValue[] parameters = new ReturnValue[tree.getChildren().Count]; 150 | int i = 0; 151 | foreach (AST parameter in tree.getChildren()) 152 | { 153 | parameters[i] = execute(parameter); 154 | i++; 155 | } 156 | returnValue = functionCall(parameters); 157 | } 158 | else 159 | { 160 | throw new Error("Can't find external function " + tree.getTokenString(), Error.ErrorType.UNDEFINED, tree.getToken().LineNr, tree.getToken().LinePosition); 161 | } 162 | } 163 | else 164 | { 165 | // Call user defined function 166 | string functionName = tree.getTokenString(); 167 | AST functionTree = getFunctionTreeNode(functionName); 168 | Assert.IsNotNull(functionTree); 169 | 170 | // Create list of parameter values 171 | List parameterValues = new List(); 172 | List functionCallChildNodes = tree.getChildren(); 173 | if (functionCallChildNodes != null) 174 | { 175 | foreach(AST parameter in tree.getChildren()) 176 | { 177 | ReturnValue val = execute(parameter); 178 | parameterValues.Add(val); 179 | } 180 | } 181 | 182 | returnValue = function(functionTree, parameterValues); 183 | } 184 | 185 | return returnValue; 186 | } 187 | 188 | private ReturnValue function(AST tree, List parameterValues) { 189 | 190 | // Push scope 191 | Scope m_previousScope = m_currentScope; 192 | AST_FunctionDefinitionNode functionDefinitionNode = (AST_FunctionDefinitionNode)(tree); 193 | Assert.IsNotNull(functionDefinitionNode); 194 | m_currentScope = (Scope)functionDefinitionNode.getScope(); 195 | Assert.IsNotNull(m_currentScope); 196 | 197 | // Push memory space 198 | MemorySpace m_previousMemorySpace = m_currentMemorySpace; 199 | MemorySpace functionMemorySpace = 200 | new MemorySpace(""); 201 | m_memoryStack.Push(functionMemorySpace); 202 | m_currentMemorySpace = functionMemorySpace; 203 | 204 | // Add parameters to memory space 205 | List parameterDeclarations = tree.getChild(2).getChildren(); 206 | if(parameterDeclarations != null) { 207 | 208 | if(parameterDeclarations.Count != parameterValues.Count) { 209 | m_errorHandler.errorOccured( 210 | "The number of arguments in function " + 211 | tree.getChild(1).getTokenString() + 212 | " does not match!", 213 | Error.ErrorType.SYNTAX); 214 | } 215 | 216 | foreach(AST parameter in parameterDeclarations) { 217 | varDeclaration(parameter); 218 | } 219 | } 220 | 221 | // Assign values to parameters 222 | if(parameterValues != null) { 223 | int i = 0; 224 | foreach(ReturnValue parameterValue in parameterValues) { 225 | 226 | string parameterName = parameterDeclarations[i].getChild(1).getTokenString(); 227 | assignValue(parameterName, parameterValue); 228 | i++; 229 | } 230 | } 231 | 232 | // Execute function 233 | ReturnValue returnValue = null; 234 | 235 | try { 236 | executeAllChildNodes(tree.getChild(3)); // child 3 is the function body 237 | } 238 | catch(ReturnValue functionReturnValue) { 239 | returnValue = functionReturnValue; 240 | } 241 | 242 | // Pop memory space 243 | m_memoryStack.Pop(); 244 | m_currentMemorySpace = m_previousMemorySpace; 245 | 246 | // Pop scope 247 | m_currentScope = m_previousScope; 248 | Assert.IsNotNull(m_currentScope); 249 | 250 | return returnValue; 251 | } 252 | 253 | private void returnStatement(AST tree) { 254 | ReturnValue returnValue = new ReturnValue(); 255 | if (tree.getChildren().Count > 0) 256 | { 257 | returnValue = execute(tree.getChild(0)); 258 | } 259 | if(returnValue != null) { 260 | #if WRITE_DEBUG_INFO 261 | Console.Write("Return value was: "); 262 | printReturnValue(returnValue); 263 | #endif 264 | throw returnValue; 265 | } 266 | } 267 | 268 | private void printReturnValue(ReturnValue returnValue) { 269 | if (returnValue.getType() == ReturnValueType.FLOAT) { 270 | Console.WriteLine(returnValue.FloatValue); 271 | } 272 | else if (returnValue.getType() == ReturnValueType.STRING) { 273 | Console.WriteLine(returnValue.StringValue); 274 | } 275 | else { 276 | Console.WriteLine("NULL"); 277 | } 278 | } 279 | 280 | private AST getFunctionTreeNode(string functionName) { 281 | FunctionSymbol funcSym = (FunctionSymbol)m_globalScope.resolve(functionName); 282 | if (funcSym == null) { 283 | throw new InvalidOperationException("Can't find function with name " + functionName); 284 | } 285 | return funcSym.getFunctionDefinitionNode(); 286 | } 287 | 288 | private void ifThenElse(AST tree) { 289 | 290 | // Push scope 291 | AST_IfNode ifNode = (AST_IfNode)(tree); 292 | Assert.IsNotNull(ifNode); 293 | m_currentScope = (Scope)ifNode.getScope(); 294 | Assert.IsNotNull(m_currentScope); 295 | 296 | // Evaluate conditional 297 | ReturnValue conditionalExpression = execute(tree.getChild(0)); 298 | 299 | if (conditionalExpression.FloatValue != 0) { 300 | Assert.IsNotNull(tree.getChild(1)); 301 | execute(tree.getChild(1)); 302 | } 303 | else { 304 | if (tree.getChildren().Count == 3) { 305 | Assert.IsNotNull(tree.getChild(2)); 306 | execute(tree.getChild(2)); 307 | } 308 | } 309 | 310 | // Pop scope 311 | m_currentScope = (Scope)ifNode.getScope().getEnclosingScope(); 312 | Assert.IsNotNull(m_currentScope); 313 | } 314 | 315 | private ReturnValue name(AST tree) { 316 | 317 | string name = tree.getTokenString(); 318 | ReturnValue val = null; 319 | 320 | val = m_currentMemorySpace.getValue(name); 321 | if (val == null) { 322 | val = m_globalMemorySpace.getValue(name); 323 | } 324 | 325 | Assert.IsNotNull(val); 326 | 327 | #if WRITE_DEBUG_INFO 328 | Console.WriteLine("The fetched value is of type " + val.getReturnType()); 329 | if(val.getReturnType() == ReturnType.FLOAT) { 330 | Console.WriteLine("And has value: " + val.FloatValue); 331 | } 332 | else if(val.getReturnType() == ReturnType.STRING) { 333 | Console.WriteLine("And has value: " + val.StringValue); 334 | } 335 | #endif 336 | return val; 337 | } 338 | 339 | private ReturnValue quotedString(AST tree) { 340 | ReturnValue returnValue = new ReturnValue(tree.getTokenString()); 341 | return returnValue; 342 | } 343 | 344 | private ReturnValue number(AST tree) { 345 | ReturnValue returnValue = new ReturnValue((float)Convert.ToDouble(tree.getTokenString())); 346 | return returnValue; 347 | } 348 | 349 | private ReturnValue operation(AST tree) { 350 | ReturnValue returnValue = null; 351 | 352 | float lhs = execute(tree.getChild(0)).FloatValue; 353 | float rhs = execute(tree.getChild(1)).FloatValue; 354 | 355 | if(tree.getTokenString() == "+") { 356 | returnValue = new ReturnValue(lhs + rhs); 357 | } 358 | else if(tree.getTokenString() == "-") { 359 | returnValue = new ReturnValue(lhs - rhs); 360 | } 361 | else if(tree.getTokenString() == "*") { 362 | returnValue = new ReturnValue(lhs * rhs); 363 | } 364 | else if(tree.getTokenString() == "/") { 365 | returnValue = new ReturnValue(lhs / rhs); 366 | } 367 | else if(tree.getTokenString() == "<") { 368 | float v = lhs < rhs ? 1 : 0; 369 | returnValue = new ReturnValue(v); 370 | } 371 | else if(tree.getTokenString() == ">") { 372 | float v = lhs > rhs ? 1 : 0; 373 | returnValue = new ReturnValue(v); 374 | } 375 | else if(tree.getTokenString() == "<=") { 376 | float v = lhs <= rhs ? 1 : 0; 377 | returnValue = new ReturnValue(v); 378 | } 379 | else if(tree.getTokenString() == ">=") { 380 | float v = lhs >= rhs ? 1 : 0; 381 | returnValue = new ReturnValue(v); 382 | } 383 | else if(tree.getTokenString() == "==") { 384 | float v = lhs == rhs ? 1 : 0; 385 | returnValue = new ReturnValue(v); 386 | } 387 | else if(tree.getTokenString() == "!=") { 388 | float v = lhs != rhs ? 1 : 0; 389 | returnValue = new ReturnValue(v); 390 | } 391 | else if(tree.getTokenString() == "&&") { 392 | float v = ((lhs != 0 ? true : false) && (rhs != 0 ? true : false)) ? 1 : 0; 393 | returnValue = new ReturnValue(v); 394 | } 395 | else if(tree.getTokenString() == "||") { 396 | float v = ((lhs != 0 ? true : false) || (rhs != 0 ? true : false)) ? 1 : 0; 397 | returnValue = new ReturnValue(v); 398 | } 399 | else { 400 | throw new NotImplementedException("Operator " + tree.getTokenString() + " isn't implemented yet!"); 401 | } 402 | 403 | return returnValue; 404 | } 405 | 406 | public ErrorHandler getErrorHandler() { return m_errorHandler; } // TODO: remove this getter, it's unnecessary 407 | 408 | AST m_ast; 409 | ExternalFunctionCreator m_externalFunctionCreator; 410 | ErrorHandler m_errorHandler; 411 | Scope m_globalScope; 412 | Scope m_currentScope; 413 | MemorySpace m_globalMemorySpace; 414 | MemorySpace m_currentMemorySpace; 415 | Stack m_memoryStack = new Stack(); 416 | } 417 | 418 | } 419 | 420 | -------------------------------------------------------------------------------- /ProgrammingLanguageNr1/src/4. Create scope tree/ScopeBuilder.cs: -------------------------------------------------------------------------------- 1 | //#define WRITE_DEBUG_INFO 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Text; 7 | 8 | namespace ProgrammingLanguageNr1 9 | { 10 | public class ScopeBuilder 11 | { 12 | public ScopeBuilder (AST ast, ErrorHandler errorHandler) 13 | { 14 | Debug.Assert(ast != null); 15 | Debug.Assert(errorHandler != null); 16 | 17 | m_errorHandler = errorHandler; 18 | m_ast = ast; 19 | } 20 | 21 | public void process() { 22 | m_globalScope = new Scope(Scope.ScopeType.MAIN_SCOPE, "global scope"); 23 | m_currentScope = m_globalScope; 24 | 25 | #if WRITE_DEBUG_INFO 26 | Console.WriteLine("Evaluate scope declarations:"); 27 | #endif 28 | 29 | evaluateScopeDeclarations(m_ast); 30 | 31 | #if WRITE_DEBUG_INFO 32 | Console.WriteLine("\nEvaluate references:"); 33 | #endif 34 | 35 | evaluateReferences(m_ast); 36 | } 37 | 38 | private void evaluateScopeDeclarations(AST tree) { 39 | Debug.Assert(tree != null); 40 | 41 | if (tree.getTokenType() == Token.TokenType.FUNC_DECLARATION) 42 | { 43 | evaluateFunctionScope(tree); 44 | } 45 | else if (tree.getTokenType() == Token.TokenType.IF) { 46 | evaluateIfScope(tree); 47 | } 48 | else if (tree.getTokenType() == Token.TokenType.LOOP) { 49 | evaluateLoopScope(tree); 50 | } 51 | else if (tree.getTokenType() == Token.TokenType.LOOP_BLOCK) { 52 | evaluateLoopBlockScope(tree); 53 | } 54 | else if (tree.getChildren() != null) 55 | { 56 | evaluateScopeDeclarationsInAllChildren(tree); 57 | } 58 | } 59 | 60 | private void evaluateScopeDeclarationsInAllChildren(AST tree) 61 | { 62 | foreach (AST subtree in tree.getChildren()) 63 | { 64 | evaluateScopeDeclarations(subtree); 65 | } 66 | } 67 | 68 | private void evaluateFunctionScope(AST tree) 69 | { 70 | // Define function name 71 | ReturnValueType returnType = ExternalFunctionCreator.GetReturnTypeFromString(tree.getChild(0).getTokenString()); 72 | string functionName = tree.getChild(1).getTokenString(); 73 | 74 | Symbol functionScope = new FunctionSymbol(m_currentScope, functionName, returnType, tree); 75 | 76 | m_globalScope.define(functionScope); // all functions are saved in the global scope 77 | 78 | m_currentScope = (Scope)functionScope; 79 | AST_FunctionDefinitionNode functionCallNode = (AST_FunctionDefinitionNode)(tree); 80 | functionCallNode.setScope((Scope)functionScope); 81 | 82 | #if WRITE_DEBUG_INFO 83 | Console.WriteLine("\nDefined function with name " + functionName + " and return type " + returnType); 84 | #endif 85 | 86 | // Process the body of the function 87 | evaluateScopeDeclarations(tree.getChild(3)); 88 | 89 | m_currentScope = m_currentScope.getEnclosingScope(); // pop scope 90 | } 91 | 92 | private void evaluateIfScope(AST tree) 93 | { 94 | Scope subscope = new Scope(Scope.ScopeType.IF_SCOPE,"", m_currentScope); 95 | 96 | m_currentScope = subscope; 97 | 98 | AST_IfNode ifNode = (tree as AST_IfNode); 99 | Debug.Assert(ifNode != null); 100 | 101 | #if WRITE_DEBUG_INFO 102 | Console.WriteLine("\nDefined IF-subscope for ifNode at line " + ifNode.getToken().LineNr); 103 | #endif 104 | 105 | ifNode.setScope(subscope); // save the new scope in the IF-token tree node 106 | 107 | // Evaluate expression 108 | evaluateScopeDeclarationsInAllChildren(tree.getChild(0)); 109 | 110 | AST trueNode = ifNode.getChild(1); 111 | AST falseNode = null; 112 | if (ifNode.getChildren().Count == 3) 113 | { 114 | falseNode = ifNode.getChild(2); 115 | } 116 | 117 | evaluateScopeDeclarationsInAllChildren(trueNode); 118 | if (falseNode != null) 119 | { 120 | evaluateScopeDeclarationsInAllChildren(falseNode); 121 | } 122 | 123 | m_currentScope = m_currentScope.getEnclosingScope(); // pop scope 124 | } 125 | 126 | static int loopSubscopes = 0; 127 | 128 | private void evaluateLoopScope(AST tree) 129 | { 130 | Scope subscope = new Scope(Scope.ScopeType.LOOP_SCOPE, "", m_currentScope); 131 | m_currentScope = subscope; 132 | 133 | #if WRITE_DEBUG_INFO 134 | Console.WriteLine("\nDefined LOOP-subscope"); 135 | #endif 136 | 137 | AST_LoopNode loopNode = (tree as AST_LoopNode); 138 | Debug.Assert(loopNode != null); 139 | evaluateScopeDeclarationsInAllChildren(loopNode); 140 | loopNode.setScope(m_currentScope); 141 | 142 | m_currentScope = m_currentScope.getEnclosingScope(); // pop scope 143 | } 144 | 145 | static int loopBlockSubscopes = 0; 146 | 147 | private void evaluateLoopBlockScope(AST tree) 148 | { 149 | Scope subscope = new Scope(Scope.ScopeType.LOOP_BLOCK_SCOPE, "", m_currentScope); 150 | m_currentScope = subscope; 151 | 152 | #if WRITE_DEBUG_INFO 153 | Console.WriteLine("\nDefined LOOP BLOCK-subscope"); 154 | #endif 155 | 156 | AST_LoopBlockNode loopBlockNode = (tree as AST_LoopBlockNode); 157 | Debug.Assert(loopBlockNode != null); 158 | evaluateScopeDeclarationsInAllChildren(loopBlockNode); 159 | loopBlockNode.setScope(m_currentScope); 160 | 161 | m_currentScope = m_currentScope.getEnclosingScope(); // pop scope 162 | } 163 | 164 | private void evaluateReferences(AST tree) { 165 | Debug.Assert(tree != null); 166 | 167 | if (tree.getTokenType() == Token.TokenType.VAR_DECLARATION) 168 | { 169 | evaluateReferencesForVAR_DECLARATION(tree); 170 | } 171 | else if (tree.getTokenType() == Token.TokenType.ASSIGNMENT) 172 | { 173 | evaluateReferencesForASSIGNMENT(tree); 174 | } 175 | else if (tree.getTokenType() == Token.TokenType.ASSIGNMENT_TO_ARRAY) 176 | { 177 | evaluateReferencesForASSIGNMENT_TO_ARRAY(tree); 178 | } 179 | else if (tree.getTokenType() == Token.TokenType.ARRAY_LOOKUP) 180 | { 181 | evaluateReferencesForARRAY_LOOKUP(tree); 182 | } 183 | else if (tree.getTokenType() == Token.TokenType.FUNC_DECLARATION) 184 | { 185 | evaluateReferencesForFUNC_DECLARATION(tree); 186 | } 187 | else if (tree.getTokenType() == Token.TokenType.FUNCTION_CALL) 188 | { 189 | evaluateReferencesForFUNCTION_CALL(tree); 190 | } 191 | else if (tree.getTokenType() == Token.TokenType.IF) 192 | { 193 | evaluateReferencesForIF(tree); 194 | } 195 | else if (tree.getTokenType() == Token.TokenType.NAME) 196 | { 197 | evaluateReferencesForNAME(tree); 198 | } 199 | else if (tree.getTokenType() == Token.TokenType.LOOP_BLOCK) 200 | { 201 | evaluateReferencesForLOOP_BLOCK(tree); 202 | } 203 | else if (tree.getTokenType() == Token.TokenType.LOOP) 204 | { 205 | evaluateReferencesForLOOP(tree); 206 | } 207 | else 208 | { 209 | evaluateReferencesInAllChildren(tree); 210 | } 211 | } 212 | 213 | private void evaluateReferencesInAllChildren(AST tree) 214 | { 215 | if (tree.getChildren() != null) 216 | { 217 | // Go through all other subtrees 218 | foreach (AST subtree in tree.getChildren()) 219 | { 220 | evaluateReferences(subtree); 221 | } 222 | } 223 | } 224 | 225 | private void evaluateReferencesForASSIGNMENT(AST tree) 226 | { 227 | AST_Assignment assignment = tree as AST_Assignment; 228 | 229 | Symbol variableNameSymbol = m_currentScope.resolve(assignment.VariableName); 230 | if(variableNameSymbol == null) { 231 | m_errorHandler.errorOccured("Can't assign to undefined variable " + assignment.VariableName, 232 | Error.ErrorType.SYNTAX, 233 | tree.getToken().LineNr, 234 | tree.getToken().LinePosition); 235 | } 236 | 237 | evaluateReferencesInAllChildren(tree); 238 | } 239 | 240 | private void evaluateReferencesForASSIGNMENT_TO_ARRAY(AST tree) 241 | { 242 | AST_Assignment assignment = tree as AST_Assignment; 243 | 244 | Symbol variableNameSymbol = m_currentScope.resolve(assignment.VariableName); 245 | if(variableNameSymbol == null) { 246 | m_errorHandler.errorOccured("Can't assign to undefined array " + assignment.VariableName, 247 | Error.ErrorType.SYNTAX, 248 | tree.getToken().LineNr, 249 | tree.getToken().LinePosition); 250 | } 251 | 252 | evaluateReferencesInAllChildren(tree); 253 | } 254 | 255 | private void evaluateReferencesForARRAY_LOOKUP(AST tree) 256 | { 257 | AST lookup = tree; 258 | 259 | Symbol variableNameSymbol = m_currentScope.resolve(lookup.getTokenString()); 260 | 261 | if(variableNameSymbol == null) { 262 | m_errorHandler.errorOccured("Can't lookup in undefined array " + lookup.getTokenString(), 263 | Error.ErrorType.SYNTAX, 264 | lookup.getToken().LineNr, 265 | lookup.getToken().LinePosition); 266 | } 267 | 268 | evaluateReferencesInAllChildren(tree); 269 | } 270 | 271 | private void evaluateReferencesForVAR_DECLARATION(AST tree) 272 | { 273 | AST_VariableDeclaration varDeclaration = tree as AST_VariableDeclaration; 274 | 275 | ReturnValueType typeToDeclare = varDeclaration.Type; 276 | string variableName = varDeclaration.Name; 277 | 278 | if (m_currentScope.isDefined(variableName)) 279 | { 280 | m_errorHandler.errorOccured( 281 | new Error("There is already a variable called '" + variableName + "'", 282 | Error.ErrorType.LOGIC, 283 | tree.getToken().LineNr, 284 | tree.getToken().LinePosition)); 285 | } 286 | else 287 | { 288 | m_currentScope.define(new VariableSymbol(variableName, typeToDeclare)); 289 | #if WRITE_DEBUG_INFO 290 | Console.WriteLine("Defined variable with name " + variableName + " and type " + typeToDeclare + " (on line " + tree.getToken().LineNr + ")" + " in " + m_currentScope); 291 | #endif 292 | } 293 | } 294 | 295 | private void evaluateReferencesForFUNCTION_CALL(AST tree) 296 | { 297 | // Function name: 298 | string functionName = tree.getTokenString(); 299 | 300 | var sym = m_currentScope.resolve (functionName); 301 | 302 | FunctionSymbol function = sym as FunctionSymbol; 303 | 304 | if (function == null) 305 | { 306 | m_errorHandler.errorOccured("Can't find function with name " + functionName, 307 | Error.ErrorType.SCOPE, 308 | tree.getToken().LineNr, 309 | tree.getToken().LinePosition 310 | ); 311 | } 312 | else 313 | { 314 | #if WRITE_DEBUG_INFO 315 | Console.WriteLine("Resolved function call with name " + functionName + " (on line " + tree.getToken().LineNr + ")"); 316 | #endif 317 | 318 | // Parameters 319 | evaluateReferencesInAllChildren(tree); 320 | 321 | AST node = function.getFunctionDefinitionNode(); 322 | AST_FunctionDefinitionNode functionDefinitionTree = (AST_FunctionDefinitionNode)(node); 323 | 324 | /*if(functionDefinitionTree.getTokenString() != "") { 325 | evaluateReferencesForFUNC_DECLARATION(functionDefinitionTree); 326 | }*/ 327 | 328 | // Setup reference to Function Definition AST node 329 | AST_FunctionCall functionCallAst = tree as AST_FunctionCall; 330 | Debug.Assert(functionCallAst != null); 331 | functionCallAst.FunctionDefinitionRef = functionDefinitionTree; 332 | 333 | List calleeParameterList = functionDefinitionTree.getChild(2).getChildren(); 334 | 335 | // Check that the number of arguments is right 336 | AST callerParameterList = tree.getChild(0); 337 | List arguments = callerParameterList.getChildren(); 338 | 339 | if (arguments.Count != calleeParameterList.Count) 340 | { 341 | m_errorHandler.errorOccured( 342 | "Wrong nr of arguments to '" + functionDefinitionTree.getChild(1).getTokenString() + "' , expected " + calleeParameterList.Count + " but got " + arguments.Count 343 | , Error.ErrorType.SYNTAX, tree.getToken().LineNr, tree.getToken().LinePosition); 344 | } 345 | } 346 | } 347 | 348 | 349 | private void evaluateReferencesForIF(AST tree) 350 | { 351 | AST_IfNode ifNode = (AST_IfNode)(tree); 352 | m_currentScope = (Scope)ifNode.getScope(); // push IF-subscope 353 | evaluateReferencesInAllChildren(tree); 354 | m_currentScope = m_currentScope.getEnclosingScope(); // pop scope 355 | } 356 | 357 | private void evaluateReferencesForNAME(AST tree) 358 | { 359 | #if DEBUG 360 | if (m_currentScope == null) { 361 | throw new Exception ("m_currentScope is null"); 362 | } 363 | if (tree == null) { 364 | throw new Exception("tree is null"); 365 | } 366 | #endif 367 | 368 | Symbol symbol = m_currentScope.resolve(tree.getTokenString()); 369 | 370 | if(symbol == null) { 371 | m_errorHandler.errorOccured( 372 | new Error("Can't find variable or function '" + tree.getTokenString() + "' (forgot quotes?)", 373 | Error.ErrorType.SYNTAX, 374 | tree.getToken().LineNr, 375 | tree.getToken().LinePosition)); 376 | } 377 | else if (symbol is FunctionSymbol) { 378 | m_errorHandler.errorOccured( 379 | new Error("'" + tree.getTokenString() + "' is a function and must be called with ()", 380 | Error.ErrorType.SYNTAX, 381 | tree.getToken().LineNr, 382 | tree.getToken().LinePosition)); 383 | } 384 | 385 | #if WRITE_DEBUG_INFO 386 | Console.WriteLine("Resolved symbol with name " + tree.getTokenString() + " (on line " + tree.getToken().LineNr + ")" + " in " + m_currentScope); 387 | #endif 388 | 389 | evaluateReferencesInAllChildren(tree); 390 | } 391 | 392 | private void evaluateReferencesForFUNC_DECLARATION(AST tree) 393 | { 394 | string functionName = tree.getChild(1).getTokenString(); 395 | m_currentScope = (Scope)m_currentScope.resolve(functionName); // push the scope with the function 396 | 397 | #if WRITE_DEBUG_INFO 398 | Console.WriteLine("\n Trying to resolve function parameters and body of " + functionName); 399 | #endif 400 | 401 | evaluateReferencesInAllChildren(tree.getChild(2)); // parameters 402 | evaluateReferencesInAllChildren(tree.getChild(3)); // function body 403 | 404 | m_currentScope = m_currentScope.getEnclosingScope(); // pop scope 405 | } 406 | 407 | private void evaluateReferencesForLOOP_BLOCK(AST tree) 408 | { 409 | AST_LoopBlockNode loopBlockNode = tree as AST_LoopBlockNode; 410 | m_currentScope = loopBlockNode.getScope(); 411 | 412 | #if WRITE_DEBUG_INFO 413 | Console.WriteLine("\n Trying to resolve body of loop block"); 414 | #endif 415 | 416 | evaluateReferencesInAllChildren(tree); 417 | 418 | m_currentScope = m_currentScope.getEnclosingScope(); // pop scope 419 | } 420 | 421 | private void evaluateReferencesForLOOP(AST tree) 422 | { 423 | AST_LoopNode loopBlockNode = tree as AST_LoopNode; 424 | m_currentScope = loopBlockNode.getScope(); 425 | 426 | #if WRITE_DEBUG_INFO 427 | Console.WriteLine("\n Trying to resolve body of loop"); 428 | #endif 429 | 430 | evaluateReferencesInAllChildren(tree); 431 | 432 | m_currentScope = m_currentScope.getEnclosingScope(); // pop scope 433 | } 434 | 435 | public Scope getGlobalScope() { 436 | Debug.Assert(m_globalScope != null, "The global scope is null, this probably means that you haven't called process() on ScopeBuilder"); 437 | return m_globalScope; 438 | } 439 | 440 | AST m_ast; 441 | Scope m_globalScope; 442 | Scope m_currentScope; 443 | ErrorHandler m_errorHandler; 444 | } 445 | } 446 | 447 | --------------------------------------------------------------------------------