PYT++

ett språk baserat på Python och C++

av

Gustav Hjortsparre

och

Robin Merell

Innehållsförteckning

Inledning	sid. 3

Användarhandledning	sid. 4

Installation	sid. 4

Kort om Pyt++ och dess syntax	sid. 4

Deklaration	sid. 5

Jämförelseoperatorer	sid. 5

If-sats	sid. 5

For-loop	sid. 6

While-loop	sid. 6

Listor	sid. 6

Print	sid. 7

Funktioner	sid. 7

Erfarenheter och reflektioner	sid. 8

Grammatik	sid. 10

Program-koden	sid. 12

Nod trädet	sid. 20

RD-Parsern	sid. 31

Inledning:

Denna dokumentation är skriven för att beskriva programmeringspråket ”Pyt++”.

Pyt++ är ett projektarbete i kursen TDP019.

Språket är en blandning mellan de två språken, Python och C++. Syftet med Pyt++ är att det ska vara ett ”nybörjarspråk” för den ovane programmeraren, därför är syntaxen relativt enkel och rakt på sak. Dock finns de flesta saker som vana programmerare förväntar sig på ett språk, såsom loopar, funktioner och t.ex. listor.

Pyt++, innehåller grunderna av de bägge språken, som nämnt ovan, och är tänkt som en introduktion till programmering för främst gymnasieelever.

Användarhandledning

Installation

Språket är packat som en .tar fil som behövs packas upp på ett lämpligt ställe, t.ex. under mappen ”Pyt++”. Om den mappen inte finns, skapa den.

Språket ”Pyt++”, Startas igenom att man öppnar Terminalen eller Kommando tolken beroende på vilket Operativsystem användaren använder.

Därefter går ni till mappen du skapade och förvarar de uppackade filerna och skriv därefter in ”ruby Pyt++.rb” i kommandotolken(För att detta ska fungera krävs att Ruby finns installerat på datorn). Ifall detta har gjorts korrekt så kommer:

Pyt++>>_

visas på displayen.

Därefter går det bra att skriva in sin kod med Pyt++ syntax.

Kort om Pyt++ och dess syntax

Språket kan hantera majoriteten av vad de bägge C baserade språken Python och C++ kan, dock är språket inte fullständigt objekt orienterat, det kan till exempel inte hantera klasser, då vi ansåg att detta program som nybörjarspråk ska fokusera på grunderna och inte slänga in er i klasser riktigt än.

Pyt++ använder en syntax som är lik den C++ använder, dock är den förenklad då man inte behöver deklarera variabel typ och liknande, precis som i Python. Sedan kräver syntaxen också ”brackets”, eller ”måsvingar”, på ett sådant sätt att de ”innesluter” koden man skriver vilket gör det lättare att se vad som hänger ihop med vad. Ett exempel på detta synes nedan:

def test() {

print ”Koden är innesluten med {} dvs brackets”

}

Pyt++ kan t.ex. hantera:

uträkningar likt, 1+1, 34*65 och dylikt

deklareringar likt , onestring = ”hejsan” och onenumber = 5

loopar såsom, if(hej == ”hejsan”){ hej;} och for(sak = 0; sak<10; sak++){sak;}

Enkel variabel addition och subtraktion kan göras genom att lägga till ++ eller – efter variabelns namn, tex. hej++ || hej-- och resulterar då i +1 eller -1.

Deklaration

I Pyt++ kan man deklarera variabler som i vilket annat språk som helst. I den processen använder vi en mer Python lik syntax då man inte behöver deklarera variabel typen likt C++, utan man behöver enbart skriva variabelnamnet följt av ett ”=” och dess nya värde:

string_variable = ”string”;

number_variable = 23;

Jämförelseoperatorer

I Pyt++ använder vi oss av lite olika jämförelseoperatorer för att kunna få ut det vi vill i t.ex. en if-sats. De som finns att tillgå är :

”==” = en vanlig jämförelse mellan två föremål

”<” = är vänstra sidan mindre än den högra

”>” = är vänstra sidan större än den högra

”<=” = är vänstra sidan mindre än eller lik med den högra

”>=” = är vänstra sin större än eller lika md den högra

”!=” = är vänster sida inte lika med den högra

Dessa olika operatorer går att använda i sin kod när som helst du kan tänkas behöva en jämförelse,

eller ett booliskt värde, då dessa retunerar sant, eller falskt, beroendet på uttrycket.

Därför är dessa nödvändiga för att få If, While och For loopar att köras.

IF-loop

Loopar fungerar på lite olika sätt beroende på vilken man använder. IF-satsen innebär att villkoret ,som står mellan parenteserna, måste uppfyllas om koden inuti IF-satsen ska köras, t.ex. i exemplet nedanför måste variabeln hej vara lika med strängen ”hejsan” och om detta uppfylls så skrivs variabel hej ut. Om detta dock inte uppfylls och hej inte är lika med ”hejsan” så görs ingenting och programmet hoppar över koden inuti IF-satsen.

if(hej == ”hejsan”) {

hej;

}

For-loop

For-loopen däremot fungerar på ett lite annat sätt. Om man tar och går igenom exemplet nedanför igen så ser vi att vi har deklarerat en variabel ”sak” och gett den värdet 0, detta måste alltid göras i For-loopen. Dock kan värdet vara vilket nummer som helst då detta bara är ett start värde som sedan ska ändras för att köra koden ett visst antal gånger. Det som sedan händer i exemplet är att vi gör en jämförelse mellan vår variabel ”sak” och siffran 10, så länge som variabeln ”sak” är mindre än 10 så körs koden inuti loopen. I den jämförelsen kan man även skriva ”=”, ”<=” eller ”>=”, vilka betyder ”lika med”, ”mindre än eller lika med” och ”större än eller lika med”.

Den sista delen i For-loopen adderar 1 till variabeln ”sak” för varje gång koden körs. Detta för att koden bara ska köras ett visst antal gånger och inte hålla på i oändligheten.

for(sak = 1; sak<10; sak++){

sak;

}

While-loop

While-loopen är en loop som körs så länge som uttrycket är sant, dvs det kan köras hur länge som helst. Det man måste se till är att man har ett avslut på loopen så den inte övergår i en oändlig loop. Loopen kan skrivas t.ex. så här:

while(hej != 4){

hej;

hej++;

}

Listor

Man kan göra listor i Pyt++ genom att deklarera en variabel som en lista:

hej = []; (en tom lista skapas)

Efter att detta har skrivits in har man skapat listan hej som från början är tom. När vi senare vill lägga in föremål i denna lista krävs en ny rad med kod:

hej<<23; (numret 23 läggs till i listan hej)

Nu har listan fått ett värde(23) och är inte längre tom.

Print

För att skriva ut variabler, siffror eller t.ex. text använder man ”print” på ett sådant sätt att man skriver:

print ”detta skrivs ut”;

(det som står innanför citattecknen skrivs ut och ses som vanlig text )

print 45;

(siffran 45 skrivs ut)

hej = 36;

hej;

(Utan att använda ordet ”print”, skrivs Variabeln hej med värdet 36 skrivs ut)

Erfarenheter och reflektion

När vi blev tilldelade detta projekt, att skapa vårt eget språk, så kändes det förvirrande men även inte så svårt. Dock under tiden som Anders hade sina föreläsningar, så blev det mer och mer klart att detta blir ingen lätt uppgift, vi spenderade mycket tid till att diskutera vad för språk som skulle passa oss bäst, eftersom båda saknade tidigare erfarenheter inom programmering innan vi började på IP programmet, så låg Python och C++ nära hjärtat som våra första språk vi skrivit i, så det var nästan givet att något av dom skulle verka som en bild av hur vi vill ha det.

Då vi inte kunde besluta vad vi ville med Python eller C++, så kom vi fram till att vi skulle kunna underlätta och göra språken ännu lättare för studenter och nya programmerare med samma erfarenhet som vi hade. Därav valde vi Pyt++, en blandning av de bägge C orienterade språken.

Vi hade inte mer än en ide på vad vi ville ha, och vad det skulle heta, ett bra tag. Inte förrän parallell

kursen TDP007 i Ruby, var slut kom vi igång.

Vi satte oss ner och skrev den grammatik och syntax vi ville använda, och hur vi ville att språket skulle se ut. Dock så stod vi framför det svåra valet, var vi skulle börja.

Efter en snabb briefing av Anders. Så började vi med den lexikaliska delen, den i sig var inte svår, men inte helt problemfri. Vi hade problem med att simpla saker skulle gå igenom kompilatorn och att vår Ruby kod skulle omvandlas till vår Pyt++ syntax.

Mycket visade sig att var fel skrivna reguljära uttryck, som gjorde att många av reglerna krockade med varandra och därför inte skrev ut det vi ville. Vi la till en massa saker som vi tycker är viktiga för programmerare och för språk generellt, dock när vi nästan kände oss klara, var vi tvungna att skriva ett Nod-träd, för att koden skulle exekveras på korrekt sätt.

Här stötte vi på mest problem, dels för att Seval, dvs, evaluering av koden och utförandet av syntaxen. Vi kunde pricka av variabel och konstant uträkning snabbt.

Mycket av kodandet i sig för nod träden och uträkningen var inte krångligt eller svårt, det vi stötte på problem med var snarare som sagt ovan, Seval som inte gjorde som vi ville, vi fick lite hjälp och tips om hur det skulle skrivas, och att det skulle köras genom lexern och inte igenom nodträdet, när vi gjorde detta, så var skapandet av, If, For och while inte svårt, och kändes som ett jättesteg för språket i sig.

Vi har ändrat en del från vår ursprungliga språkspecifikation, såsom att vi har delat upp sakerna på ett bättre sätt än innan. Detta gjorde vi för att förenkla vår kod och för att få saker att fungera som vi ville. Men de stora sakerna som t.ex. if-satser och dylikt är desamma som i den första språkspecifikationen.

Även ändrat saker som syntax viss och rent generellt inte passade in för det språk vi ville skapa och inte uppfyllde kravet vi hade, dvs att vara enkelt, utan snarare försvårade och skulle förvirra användaren.

Andra viktiga små delar i koden har vi fått dela upp, för att inte vara för generella, utan så att vi kan komma åt dom på specifika områden.

Vi känner att vi har lärt oss mycket under den här kursen och speciellt då om Ruby och hur man kan använda språket för så mycket olika saker. Det är intressant att man bygger sitt eget språk genom att skriva kod i ett annat redan befintligt språk. Det var inte vad vi trodde innan kursen började.

Själva kunskaperna i Ruby-programmering har också den ökat mycket sedan vi började med TDP019, vilket är mycket bra då vi båda kände att vi behövde bättra på dom mer efter TDP007 kursen.

Dock den viktigaste läxan är planering, gör man detta bra från början och grundligt så sparar man mycket tid. Vi skulle behöva göra detta mycket bättre, vi vet att vi skulle uppnåt mycket mer då.

Grammatik

BEGIN	: STATEMENTS

STATEMENTS	: STATEMENTS ; STMT

: STMT

STMT	: FUNCTION

: IF EXPR

: FOR EXPR

: WHILE EXPR

: LIST

: DECL

: INCREMENT

: RETURN

IF EXPR	: if ( BOOL_EXPR ){

STATEMENTS}

FOR EXPR	: for( VARIABLE ';' BOOL_EXPR';' INCREMENT){

STATEMENTS }

: for( DECL ';' BOOL_EXPR ';' INCREMENT){

STATEMENTS}

WHILE EXPR	:while(BOOL_EXP){

STATEMENTS }

IDENTIFIER	: [a-zA-z]+

VARIABLE	:IDENTIFIER

ARIT_EXPR	: DIGIT '+' DIGIT

: DIGIT '-' DIGIT

: DIGIT '*' DIGIT

: DIGIT '/' DIGIT

:VARIABLE '+' VARIABLE

:VARIABLE '-' VARIABLE

:VARIABLE '+' DIGIT

:VARIABLE '-' DIGIT

DIGIT	: [0-9]+

BOOLEXP	: DIGIT '==' DIGIT

: DIGIT '!=' DIGIT

: VARIABLE '==' DIGIT

: VARIABLE '!=' DIGIT

: VARIABLE '<=' DIGIT

: VARIABLE '>=' DIGIT

OP_ASS	: == | < | > | >= | <=

LIST	: VARIABLE '=' [ ]

: VARIABLE '<<' DIGIT

: VARIABLE '<<' IDENTIFIER

: VARIABLE '>>' DIGIT

: VARIABLE '>>' '[ ' DIGIT || IDENTIFIER ']'

: VARIABLE '[' DIGIT ']'

: VARIABLE '(' DIGIT ')' '<<' DIGIT || IDENTIFIER

DECL	: GET_VARIABLE

: GET_VARIABLE

: GET_VARIABLE = DIGIT

: GET_VARIABLE = IDENTIFIER

: GET_VARIABLE = ARIT_EXPR

RETURN	:'print' IDENTIFIER

:'print' ARIT_EXPR

:'print' ”[a-zA-Z]+\s?[a-zA-Z]+”

:IDENTIFIER

:DIGIT

INCREMENT	:VARIABLE '++'

:VARIABLE '--'

Program-koden

require 'Pyt.rb'

require 'syntax.rb'

require 'logger'

# Pyt++

#Skapad av Gustav Hjortsparre & Robin Merell

class PytLex

def initialize

@PytParser = Parser.new('Pyt++') do

token(/\d+/) {|m|m.to_i }

token(/\w+/){|m|m}

token(/\s+/)

token(/./){|m|m}

start :begin do

match(:statements)

end

rule :statements do

match(:statements,';',:stmt){|stmts,_,stmt,_| Statement_nod.new(stmts, stmt)}

match(:stmt) {|stmt|

stmt}

end

rule :stmt do

match(:ifexpr)

match(:forexpr)

match(:whileexpr)

match(:list)

match(:decl)

match(:increment)

match(:return)

end

rule :ifexpr do

match('if','(',:bool_exp,')','{',:statements,'}'){|_,_,a,_,_,b,_|

s = If_stmt_nod.new(a,b)

}

end

rule :whileexpr do

match('while','(',:bool_exp,')','{',:statements,'}'){|_,_,a,_,_,b,_|

w = While_loop_nod.new(a,b)

}

end

rule :forexpr do

match('for','(',:variable,';', :bool_exp,';', :increment,')','{',:statements,'}'){|_,_,a,_,b,_,c,_,_,d,_|

f = For_loop_nod.new(a,b,c,d)

}

match('for','(',:decl,';',:bool_exp,';', :increment, ')', '{' ,:statements, '}' ) {|_,_,a,_,b,_,c,_,_,d,_|

f = For_loop_decl_nod.new(a,b,c,d)

}

end

rule :list do

match(:variable,'[',:digit,']'){|a,_,b,_|

l = List_find_nod.new(a,b)

}

match(:variable, '<','<',:digit){|a,_,_,b|

l = List_append_nod.new(a,b)

}

match(:variable, '<','<',:identifier){|a,_,_,b|

l = List_append_nod.new(a,b)

}

match(:variable, '=', '[',']'){|a,_,_,_|

l = List_nod.new(a)

}

match(:variable, '>','>','[',:digit,']'){|a,_,_,_,b,_|

l = List_delete_nod.new(a,b)

}

match(:variable, '>','>',:digit){|a,_,_,b|

l = List_delete_spec_nod.new(a,b)

}

match(:variable,'>','>',:identifier){|a,_,_,b|

l = List_delete_spec_nod.new(a,b)

}

match(:variable,'(',:digit,')','<','<',:digit){|a,_,b,_,_,_,c|

l = List_find_append_nod.new(a,b,c)

}

match(:variable,'(',:digit,')','<','<', :identifier){|a,_,b,_,_,_,c|

l = List_find_append_nod.new(a,b,c)

}

end

rule :decl do

match(:variable,'=',:digit){|a,_,b|

c = Tilldelning_nod.new(a,b)

}

match(:variable,'=',:digit_float){|a,_,b|

c = Tilldelning_nod.new(a,b)

}

match(:variable, '=',:arit_expr){|a,_,b|

c = Tilldelning_nod.new(a,b)

}

match(:variable, '=',:identifier){|a,_,b|

c = Tilldelning_nod.new(a,b)

}

match(:arit_expr)

end

rule :increment do

match(:variable,'+','+'){|var,op,_|

a = Addition_nod.new(var,op)

}

match(:variable,'-','-'){|var,op,_|

a = Addition_nod.new(var,op)

}

end

rule :bool_exp do

match(:digit, '=','=', :digit){|dig,op,op4,dig2|

op+=op4

s = Sammansatt_aritm_nod.new(op,dig,dig2)

}

match(:digit, '!', '=', :digit){|dig,op,op4,dig2|

op+=op4

s = Sammansatt_aritm_nod.new(op,dig,dig2)

}

match(:variable, '=','=',:digit){|var,op,op4,dig|

op+=op4

s = Sammansatt_dig_nod.new(var,dig,op)

}

match(:variable, '=', '=', :variable){|var,op,op4,var2|

op+=op4

s = Sammansatt_var_nod.new(var,var2,op)

}

match(:variable, '!','=',:digit){|var,op,op4,dig|

op+=op4

s = Sammansatt_dig_nod.new(var,dig,op)

}

match(:variable, '!', '=', :variable){|var,op,op4,var2|

op+=op4

s = Sammansatt_var_nod.new(var,var2,op)

}

match(:variable,'<',:digit){|var,op,dig|

s = Sammansatt_dig_nod.new(var,dig,op)

}

match(:variable, '>', :digit){|var,op,dig|

s = Sammansatt_dig_nod.new(var,dig,op)

}

match(:variable,'<','=', :digit){|var,op,op4,dig|

op+=op4

s= Sammansatt_dig_nod.new(var,dig,op)

}

end

rule :arit_expr do

match(:digit, '+', :digit ){|dig,op, dig2|

s = Sammansatt_aritm_nod.new(op,dig,dig2)

}

match(:digit, '-', :digit){|dig,op,dig2|

s = Sammansatt_aritm_nod.new(op,dig,dig2)

}

match(:digit, '*', :digit){|dig,op,dig2|

s = Sammansatt_aritm_nod.new(op,dig,dig2)

}

match(:digit, '/', :digit){|dig,op,dig2|

s = Sammansatt_aritm_nod.new(op,dig,dig2)

}

match(:variable, '+', :variable){|var,op,var2|

s = Sammansatt_var_nod.new(var,var2,op)

}

match(:variable, '-', :variable){|var,op,var2|

s = Sammansatt_var_nod.new(var,var2,op)

}

match(:variable, '+', :digit){|var,op,dig|

s = Sammansatt_dig_nod.new(var,dig,op)

}

match(:variable, '-', :digit){|var,op,dig|

s = Sammansatt_dig_nod.new(var,dig,op)

}

end

rule :return do

match('print', :arit_expr){|_,a|

p = Print_nod_seval.new(a)

}

match('print', :digit){|_,a|

p = Print_nod.new(a)

}

match('print', :identifier){|_,a|

p = Print_nod.new(a)

}

match('print','"', /([a-z]+\s?\w+)+/,'"'){|_,_,a,_|

p = Print_nod.new(a)

}

match(:variable){|a|

r = Return_variabel_nod.new(a)

}

match(:digit){|a|

p = Print_nod.new(a)

}

end

rule :digit do

match(Integer){|a|a

}

end

rule :identifier do

match(/([a-zA-Z])+/){|a|

a

}

end

rule :variable do

match(:identifier){|a|

Variabel_nod.new(a)

}

end

end

def exitprog(str)

['exit'].include?(str.chomp)

end

def roll(str =" ")

if str == " "

print "Pyt++>>"

str = gets

if exitprog(str) then

puts "Exiting Pyt++"

else

parsetree = @PytParser.parse(str)

puts parsetree

puts parsetree.seval

roll

end

else

@PytParser.parse str

end

end

end

end

test = PytLex.new.roll()

Nod-Trädet

# Node tree

# Pyt++ Syntax

#

# This file includes all the nodes and calculations that makes Pyt++ run

#

# Created by: Gustav Hjortsparre and Robin Merell

@@omg = {}

def look_up(var, omg) # Looks up the values in the hashtable.

omg[var] # The omg hash, controls and saves all the variables

end

class Statement_nod

attr_accessor :Statements, :Stmt

def initialize (stmts , stmt)

@Statements = stmts

@Stmt = stmt

end

def seval()

test = Array.new

while @Stmt != nil do

test << @Statements

test << @Stmt

@Stmt = nil

end

return test.each{|x| x.seval}

end

end

class Konstant_nod # <konstant> ::= Ruby-numbers

attr_accessor :val

def initialize (int)

@val = int

end

def seval()

return @val

end

end

class Variabel_nod # <variable> ::= Ruby-string

attr_accessor :namn

def initialize(id)

@namn = id

end

def seval()

return look_up(@namn, @@omg)

end

end

class Type_nod #Checks what type the following variable is

attr_accessor :check

def initialize(var)

@check = var

end

def seval()

if @@omg[check.namn].class == String then puts "String"

elsif @@omg[check.namn].class == Fixnum then puts "Integer"

elsif @@omg[check.namn].class == Array then puts "List"

else puts "No declared variabel"

end

end

end

class Tilldelning_nod # Gives the given Variable a value, it can be either a String or a Digit

attr_accessor :var, :tilldelnings_uttryck

def initialize(var, uttr)

@var=var

@tilldelnings_uttryck = uttr

end

def seval()

varde = tilldelnings_uttryck

puts "--> seval-gives " + var.namn + " = #{varde} \n"

@@omg[var.namn] = varde

return @@omg[var.namn]

end

end

class Addition_nod #Increment Node, adds 1 or subtracts 1 from the given Variable

attr_accessor :var, :op

def initialize(var,op)

@var = var

@op = op

end

def seval()

if @@omg[@var.namn] == nil then p "This Variabel has no value declared to it."

else

case op

when operator = '+'

puts "Seval gives --> " + var.namn + " = " + "#{@@omg[var.namn]+1}"

@@omg[var.namn] += 1

when operator = '-'

puts "Seval gives --> " + var.namn + " = " + "#{@@omg[var.namn]-1}"

@@omg[var.namn] -= 1

end

end

end

end

class Print_nod_seval

attr_accessor :reword

def initialize(word)

@reword = word

end

def seval()

puts "Seval returns --> " + "#{reword}"

return @reword.seval

end

end

class Print_nod #Returns a given string or digit.

attr_accessor :reword

def initialize(word)

@reword = word

end

def seval()

puts "Seval returns --> " + "#{reword}"

return @reword

end

end

class Return_variabel_nod #Returns a variables value.

attr_accessor :var

def initialize(var)

@var = var

end

def seval()

if @@omg[var.namn].class == Array then

p @@omg[var.namn]

elsif @@omg[var.namn] == nil then p "No defined variabel with the name --> #{var.namn} <--"

end

return @@omg[var.namn]

end

end

class List_nod #Creates a List, that can hold any number or string

attr_accessor :list

def initialize(var)

@list = var

end

def seval()

if @@omg[list.namn] != nil then puts "Cant use already declared variabel"

else

@@omg[list.namn] = Array.new

puts "Seval creates a list --> " + "#{list.namn}"

return @@omg[list.namn]

end

end

end

class List_append_nod #Appends numbers or strings to a created List.

attr_accessor :var, :value

def initialize(var,value)

@var = var

@value = value

end

def seval()

if @@omg[var.namn].class == Array then

@@omg[var.namn] << value

puts "Seval adds to the list --> " + var.namn + " << " +"#{value}"

return @@omg[var.namn]

else

puts "#{@@omg[var.namn]}" + "is no List"

end

end

end

class List_find_nod #Searhes for a value on a certain position and returns its value that it contains.

attr_accessor :var, :find

def initialize(var,pos)

@var = var

@find = pos

end

def seval()

test = @@omg[var.namn]

if @@omg[var.namn].class != Array then p "There is no List declared with this name --> #{var.namn} <--"

elsif test[find] == nil then p "There is nothing declared at this posistion --> #{find} <--"

else

ret = test[find]

return ret

end

end

end

class List_find_append_nod #Look up a posistion, and if nothing is declared at that posistion, one can declare a number or a string.

attr_accessor :var, :find, :value

def initialize(var,pos,dig)

@var = var

@find = pos

@value = dig

end

def seval()

test = @@omg[var.namn]

if @@omg[var.namn].class != Array then p "There is no List declared with this name --> #{var.namn} <-- "

elsif test[find] != nil then puts " The position is already declared "

else ret = test[find]

test[find] = value

return ret

end

end

end

class List_delete_nod #Looks up a specified posistion in the list and then removes it from the it. Any value after the deleted one will be moved forward 1 step.

attr_accessor :var, :remove_var

def initialize(var,var2)

@var = var

@remove_var = var2

end

def seval()

test = @@omg[var.namn]

if @@omg[var.namn].class != Array then p "There is no List declared with this name --> #{var.namn} <--"

elsif test[remove_var] == nil then p "There is nothing declared on this posistion"

else

ret = test[remove_var]

test.delete_at(remove_var)

return ret

end

end

end

class List_delete_spec_nod #Looks up a value, anything that is equal to that value will be remove from that list.

attr_accessor :var, :remove_spec

def initialize(var,var2)

@var = var

@remove_spec = var2

end

def seval()

test = @@omg[var.namn]

if @@omg[var.namn].class != Array then p "There is no List declared with this name --> #{var.namn} <--"

elsif test.include?(remove_spec) == false then p "#{remove_spec} <-- Is not in the List"

else

ret = test.delete(remove_spec)

test.delete(remove_spec)

return ret

end

end

end

class Sammansatt_aritm_nod #Adds/Subtracts/Multiply/divide digits.

attr_accessor :operator, :operand1, :operand2

def initialize(op, op1, op2)

@operator = op

@operand1 = op1

@operand2 = op2

end

def seval()

case operator

when operator = '+'

p "Seval adds --> " + "#{operand1}" + " with " + "#{operand2}" + " equals #{operand1 + operand2}"

return operand1 + operand2

when operator = '-'

p "Seval subtracts --> " + "#{operand1}" + " with " + "#{operand2}" + " equals #{operand1 - operand2}"

return operand1 - operand2

when operator = '*'

p "Seval multiplies --> " + "#{operand1}" + " with " + "#{operand2}" + " equals #{operand1 * operand2}"

return operand1 * operand2

when operator = '/'

p "Seval divides --> " + "#{operand1}" + " with " + "#{operand2}" + " equals #{operand1 / operand2}"

return operand1 / operand2

when operator = '=='

p "Seval --> " + "#{operand1}" + " with " + "#{operand2}"

if operand1 == operand2 then return true

else return false

end

else

nil

end

end

end

class Aritm_nod

attr_accessor :aritm_uttr

def initialize(aritm_uttr)

@aritm_uttr = aritm_uttr

end

def seval()

return aritm_uttr.seval

end

end

class Sammansatt_dig_nod #adds a declared variable holding a integer, together with a digit.

attr_accessor :operator, :variable1, :variable2

def initialize(var1,var2,op)

@operator = op

@variable1 = var1

@variable2 = var2

end

def seval()

if @@omg[variable1.namn].class == String then p "This Variable is holding a string"

elsif @@omg[variable1.namn] == nil then p "No defined Variabel with the name ---> #{variable1.namn} <---"

else

case operator

when operator = '+'

p "Seval adds --> " + variable1.namn + " with #{variable2}"

@@omg[variable1.namn] += variable2

when operator = '-'

p "Seval subtracts --> " + variable1.namn + " with #{variable2}"

@@omg[variable1.namn] -= variable2

when operator = '=='

p "Seval --> " + variable1.namn + " with #{variable2}"

if @@omg[variable1.namn] == variable2

return true

else return false

end

when operator = '!='

p "Seval --> " + variable1.namn + " with #{variable2}"

if @@omg[variable1.namn] != variable2

return true

else return false

end

when operator = '<'

p "Seval --> " + variable1.namn + " with #{variable2}"

if @@omg[variable1.namn] < variable2

return true

else return false

end

when operator = '>'

p "Seval --> " + variable1.namn + " with #{variable2}"

if @@omg[variable1.namn] > variable2

return true

else return false

end

when operator = '<='

p "Seval --> " + variable1.namn + " with #{variable2}"

if @@omg[variable1.namn] <= variable2

return true

else return false

end

end

end

end

end

class Sammansatt_var_nod # Adds 2 variables together.

attr_accessor :operator, :variable1, :variable2

def initialize(var1,var2,op)

@operator = op

@variable1 = var1

@variable2 = var2

end

def seval()

case operator

when operator = '+'

puts "seval adds --> " + variable1.namn+" #{@@omg[variable1.namn]}" + " with " + variable2.namn+" #{@@omg[variable2.namn]}"

@@omg[variable1.namn] += @@omg[variable2.namn]

p variable1.namn + " = #{@@omg[variable1.namn]}"

when operator = '-'

puts "seval subtracts --> " + variable1.namn+" #{@@omg[variable1.namn]}" + " with " + variable2.namn+" #{@@omg[variable2.namn]}"

@@omg[variable1.namn] -= @@omg[variable2.namn]

p variable1.namn + " = #{@@omg[variable1.namn]}"

when operator = '!='

puts "seval ---> " + variable1.namn + " with " + variable2.namn

if @@omg[variable1.namn] != @@omg[variable2.namn] then return true else return false end

when operator = '=='

puts "seval --> " + variable1.namn + " with " + variable2.namn

if @@omg[variable1.namn] == @@omg[variable2.namn] then return true else return false end

else

nil

end

end

end

class If_stmt_nod #IF statement, if the statement is true it does the statement.

attr_accessor :bool, :stmt

def initialize(exp,stmt)

@bool = exp

@stmt = stmt

end

def seval()

if @bool.seval == true then

@stmt

end

return @stmt.seval

end

end

class For_loop_nod #As long as the For loop is true it does what the Statement block states.

attr_accessor :var,:bool, :incr, :stmt

def initialize(var,bool,incr,stmt)

@for_var = var

@for_bool = bool

@for_incr = incr

@for_stmt = stmt

end

def seval()

if @@omg[@for_var.namn] == nil then p "No Variabel declared with that name --> #{@@omg[@for_var.namn]} <--"

else

while @for_bool.seval do

@for_incr.seval

@for_stmt.seval

end

end

return @for_incr.seval

end

end

class For_loop_decl_nod #Does the same as the For loop, but gives the ability to declare the variable in the for loop.

attr_accessor :decl_var, :for_bool, :for_incr, :for_stmt

def initialize(var,bool,incr,stmt)

@decl_var = var

@for_bool = bool

@for_incr = incr

@for_stmt = stmt

end

def seval()

@decl_var.seval

while @for_bool.seval do

@for_incr.seval

end

return @for_stmt.seval

end

end

class While_loop_nod #As long as the bool expression is true, it will keep on doing the Statement. When it reaches false, it will abort the loop.

attr_accessor :while_var, :while_stmt

def initialize(var,stmt)

@while_var = var

@while_stmt = stmt

end

def seval()

while @while_var.seval do

@while_stmt.seval

end

return @while_stmt.seval

end

end

class Function_nod #Constructs a Function, that can handle calculations, such as anything stated above. This node does not handle any parameters.

attr_accessor :fun_name, :fun_stmt

def initialize(fun_name, stmt)

@fun_name = fun_name

@fun_stmt = stmt

end

def seval()

@@function[fun_name]

function_look_up(@fun_stmt,@@function)

@@function[fun_name] = @fun_stmt

return @fun_stmt.seval

p @@function

end

end

class Help_nod #Prints out a help section, that gives examplecode on the diffrent calculations Pyt++ can handle.

attr_accessor :help

def initialize(var)

@help = var

end

def seval()

if help == "List" then puts " - - - - - - - - - - - List - - - - - - - - - - - \n\nCreate - Variabel = [] \n\nAppend - Variabel << Value \nAppend_Pos - Variabel(position) << Value \n\nSearch - Variabel[Position] \n\nRemove(Value) - Variabel >> Value \nRemove(Position) - Variabel>>[Position]"

elsif help == "Variabel" then puts " - - - - - - - - - Variabel - - - - - - - - - \nDeclaration - a-zA-Z = Value 'Can include digits and strings' "

elsif help == 'While' then puts " - - - - - - - - - - While-Loop - - - - - - - - -\nDeclaration - while(bool_expr){statement} \nExample a=2 while(a<5){a++} \n//Keep in mind that the while loop will keep on generating the statement\n until the bool_expr is false. //"

elsif help == 'If' then puts " - - - - - - - - - - - If-Statement - - - - - - - - \nDeclaration - if(bool_expr){statement} \nExample if(2==2){print hello} \n// If the bool_expr is true, it will do everything that says in the statement box.//"

elsif help == 'For' then puts " - - - - - - - - - - - - For-Loop - - - - - - - - - - \nDeclaration(declare a variable) for(declare variable;bool_expr;increment){Statements} \nExample for(a=1;a<5;a++){print a} \nDeclare(without declaration)for(variable;bool_expr;increment){statements}\nExample - for(a;a<b;a++){a}"

elsif help == "Function" then puts " - - - - - - - - - - - Function - - - - - - - - - - - \nDeclaration - def fun(){Statements}\n "

else puts "Incorrectly inputed command \nApproved commands \n -> List \n -> Variabel \n -> While \n -> If \n -> For\n -> Function"

end

end

end

RD-Parsern

require 'logger'

class Rule

Match = Struct.new :pattern, :block

def initialize(name, parser)

@logger = parser.logger

@name = name

@parser = parser

@matches = []

@lrmatches = []

end

def match(*pattern, &block)

match = Match.new(pattern, block)

if pattern[0] == @name

pattern.shift

@lrmatches << match

else

@matches << match

end

end

def parse

match_result = try_matches(@matches)

return nil if match_result.nil?

loop do

result = try_matches(@lrmatches, match_result)

return match_result if result.nil?

match_result = result

end

end

private

def try_matches(matches, pre_result = nil)

match_result = nil

start = @parser.pos

matches.each do |match|

result = pre_result ? [pre_result] : []

match.pattern.each_with_index do |token,index|

if @parser.rules[token]

result << @parser.rules[token].parse

if result.last.nil?

result = nil

break

end

# @logger.debug("Matched '#{@name} = #{match.pattern[index..-1].inspect}'")

else

nt = @parser.expect(token)

if nt

result << nt

if @lrmatches.include?(match.pattern) then

pattern = [@name]+match.pattern

else

pattern = match.pattern

end

# @logger.debug("Matched token '#{nt}' as part of rule '#{@name} <= #{pattern.inspect}'")

else

result = nil

break

end

end

end

if result

if match.block

match_result = match.block.call(*result)

else

match_result = result[0]

end

# @logger.debug("'#{@parser.string[start..@parser.pos-1]}' matched '#{@name}' and generated '#{match_result.inspect}'") unless match_result.nil?

break

else

@parser.pos = start

end

end

return match_result

end

end

class Parser

attr_accessor :pos

attr_reader :rules, :string, :logger

class ParseError < RuntimeError

end

def initialize(language_name, &block)

@logger = Logger.new(STDOUT)

@lex_tokens = []

@rules = {}

@start = nil

@language_name = language_name

instance_eval(&block)

end

def tokenize(string)

@tokens = []

@string = string.clone

until string.empty?

raise ParseError, "unable to lex '#{string}" unless @lex_tokens.any? do |tok|

match = tok.pattern.match(string)

if match

# @logger.debug("Token #{match[0]} consumed")

@tokens << tok.block.call(match.to_s) if tok.block

string = match.post_match

true

else

false

end # if

end # raise

end # until

end

def parse(string)

tokenize(string)

@pos = 0

@max_pos = 0

@expected = []

result = @start.parse

if @pos != @tokens.size

raise ParseError, "Parse error. expected: '#{@expected.join(', ')}', found '#{@tokens[@max_pos]}'"

end

return result

end

def next_token

@pos += 1

return @tokens[@pos - 1]

end

def expect(tok)

t = next_token

if @pos - 1 > @max_pos

@max_pos = @pos - 1

@expected = []

end

return t if tok === t

@expected << tok if @max_pos == @pos - 1 && !@expected.include?(tok)

return nil

end

def to_s

"Parser for #{@language_name}"

end

private

LexToken = Struct.new(:pattern, :block)

def token(pattern, &block)

@lex_tokens << LexToken.new(Regexp.new('\\A' + pattern.source), block)

end

def start(name, &block)

rule(name, &block)

@start = @rules[name]

end

def rule(name,&block)

@current_rule = Rule.new(name, self)

@rules[name] = @current_rule

instance_eval &block

@current_rule = nil

end

def match(*pattern, &block)

@current_rule.send(:match, *pattern, &block)

end

end