online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code    Language
=begin At all times, the Forth interpreter maintains a stack of values. The program will keep reading lines from standard input. Each line is split into words and stored in a list named "word_list". The "word_list" acts as a list of pending commands. The Forth interpreter also maintains a dictionary to store user-defined new words. When the new word is encountered in the word_list, it will be replaced by its definition. Moreover, the Forth interpreter maintains another dictionary named "heap", to keep track of heap memory address. Users can name constants and save values in the heap memory through variables. =end class String # helper function def is_integer? self.to_i.to_s == self end end class Forth attr_reader :word_list, :stack, :dictionary, :heap def initialize @word_list = [] @stack = MyStack.new() @dictionary = {} @heap = {} end def eval is_exit = false # A variable to track if the "exit" command is received. is_str = false # A variable to track if a string is received. get_name = false # A varaible to track if ":" is received. new_word = "" # A variable to store the name of the new word get_def = false # A variable to track if the user is defining a new word. if_received = false # A variable to track if "if" is received. else_received = false # A variable to track if "else" is received. enter_if = false # A variable to check if TOS is -1. is_begin = false # A variable to track if "begin" is received. is_until = false # A variable to track if "until" is received. begin_num = 0 # number of words in the body of the begin loop. is_do = false # A variable to track if "do" is received. is_loop = false # A variable to track if "loop" is received. loop_counter = 0 start_index = 0 # A variable to store the start of the loop counter end_index = 0 # A variable to store the end of the loop counter. do_num = 0 # Number of words in the body of the do loop. get_const_name = false # A variable to track if "constant" is received. mem_address = 1000 # A variable to track the memory address. get_var_name = false # A variable to track if "variable" is received. while true @word_list = STDIN.gets.strip.split(" ") # for each words in the input line while @word_list.size>0 top = @word_list.shift if is_until begin_num = begin_num -1 end if is_loop do_num = do_num -1 end if get_name # get the name of the new word and store it in the dictionary new_word = top.downcase dictionary[new_word] = [] get_name = false get_def = true elsif top == ";" get_def = false elsif get_def # get the definition (a collection of other words) of the new word dictionary[new_word].push(top.downcase) elsif get_const_name dictionary[top.downcase] = @stack.top @stack = @stack.pop get_const_name = false elsif get_var_name dictionary[top.downcase] = mem_address mem_address = mem_address + 1 get_var_name = false # handle the begin loop elsif top.downcase == "until" is_begin = false if @stack.top == 0 is_until = true begin_num = dictionary["begin"].size # append the body of the loop to the front of the @word_list new_word_list = dictionary["begin"] + @word_list @word_list = new_word_list end elsif is_begin # store the body of the loop in the dictionary dictionary["begin"].push(top.downcase) elsif top.downcase == "begin" if @stack.top != 0 && @stack.top != 1 puts "Error: Wrong usage of \"begin\"" @stack = "Error" end is_begin = true dictionary["begin"] = [] # handle the do loop elsif top.downcase == "i" && is_loop @stack.push(loop_counter) elsif top.downcase == "loop" is_do = false is_loop = true loop_counter = start_index - 1 do_num = 0 elsif is_do # store the body of the loop in the dictionary dictionary["do"].push(top.downcase) elsif top.downcase == "do" if @stack.stack.size < 2 puts "Error: Stack underflow" # signal error @stack = "Error" else start_index = @stack.top @stack = @stack.pop end_index = @stack.top @stack = @stack.pop dictionary["do"] = [] is_do = true end # handle the if ... else ... then elsif top.downcase == "then" # reset if_received if_received = false # reset else_received else_received = false # reset enter_if enter_if = false elsif top.downcase == "else" else_received = true # reset if_received if_received = false elsif else_received == true && enter_if == true # ignore the words after "else" until "then" is received elsif if_received == true && enter_if == false # ignore the words after "if" until "else" or "then" is received # handle the strings elsif top == "\"" is_str = false elsif is_str print top print " " elsif top.is_integer? top = top.to_i @stack = @stack.push(top) elsif top.downcase == "exit" is_exit = true # if "exit" is received, stop reading the line break elsif dictionary.key?(top.downcase) # if the word is a user-defined new word if dictionary[top.downcase].kind_of?(Array) # append the definition of the defined new word to the front of the @word_list new_word_list = dictionary[top.downcase] + @word_list @word_list = new_word_list # else if the word is a constant or a variable else @stack.stack.push dictionary[top.downcase] end elsif top == "+" @stack = @stack.plus elsif top == "-" @stack = @stack.minus elsif top == "*" @stack = @stack.multiply elsif top == "/" @stack = @stack.divide elsif top.downcase == "mod" @stack = @stack.mod elsif top.downcase == "dup" @stack = @stack.dup elsif top.downcase == "swap" @stack = @stack.swap elsif top.downcase == "drop" @stack = @stack.drop elsif top.downcase == "dump" @stack = @stack.dump elsif top.downcase == "over" @stack = @stack.over elsif top.downcase == "rot" @stack = @stack.rot elsif top == "." @stack = @stack.dot elsif top.downcase == "emit" @stack = @stack.emit elsif top.downcase == "cr" puts "" elsif top == "=" @stack = @stack.eql elsif top == "<" @stack = @stack.less elsif top == ">" @stack = @stack.larger elsif top.downcase == "and" @stack = @stack.and elsif top.downcase == "or" @stack = @stack.or elsif top.downcase == "xor" @stack = @stack.xor elsif top.downcase == "invert" @stack = @stack.invert elsif top.downcase == ".\"" is_str = true # check if the user is defining a new word elsif top.downcase == ":" get_name = true elsif top.downcase == "if" if_received = true if @stack.top == -1 @stack = @stack.pop enter_if = true elsif @stack.top == 0 @stack = @stack.pop enter_if = false else puts "Error: Wrong usage of \"if\"" @stack = "Error" end elsif top.downcase == "constant" if @stack.stack.size < 1 puts "Error: Stack underflow" # signal error @stack = "Error" end get_const_name = true elsif top.downcase == "variable" get_var_name = true elsif top.downcase == "cell" @stack = @stack.cell elsif top.downcase == "allot" allot_size = @stack.top @stack = @stack.pop mem_address = mem_address + allot_size elsif top.downcase == "!" if @stack.stack.size < 2 puts "Error: Stack underflow" # signal error @stack = "Error" end store_address = @stack.top @stack = @stack.pop store_val = @stack.top @stack = @stack.pop heap[store_address] = store_val elsif top.downcase == "@" get_address = @stack.top @stack = @stack.pop @stack.push(heap[get_address]) else print "Error: Unknown word \"" print top.downcase puts "\"" # signal error @stack = "Error" end # if error, stop reading the line break if @stack == "Error" # finished one begin loop and determine if another loop is needed if is_until && begin_num == 0 if @stack.top == 0 @stack = @stack.pop begin_num = dictionary["begin"].size # append the body of the loop to the front of the @word_list new_word_list = dictionary["begin"] + @word_list @word_list = new_word_list else is_until = false @stack = @stack.pop end end # finished one do loop and determine if another loop is needed if is_loop && do_num == 0 loop_counter = loop_counter + 1 if loop_counter < end_index do_num = dictionary["do"].size # append the body of the loop to the front of the @word_list new_word_list = dictionary["do"] + @word_list @word_list = new_word_list else is_loop = false end end end # if error, exit the program break if @stack == "Error" # if "exit" command received, exit the program break if is_exit == true puts "ok" end end end class MyStack attr_reader :stack def initialize @stack = [] end def push(x) @stack.push x self end def pop @stack.pop self end # a helper function to get the top of the stack def top temp = @stack.pop @stack.push(temp) temp end # Adds the top two stack values and then push the result back to the stack. def plus if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop sum = a.to_i + b.to_i @stack.push(sum) self end end # Substracts the top two stack values and then push the result back to the stack. def minus if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop difference = a - b @stack.push(difference) self end end # Multiplies the top two stack values and then push the result back to the stack. def multiply if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop product = a * b @stack.push(product) self end end # Divides the top two stack values and then push the result back to the stack. def divide if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop quotient = a / b @stack.push(quotient) self end end # Calculates the division remainder for the top two stack values # and then push the result back to the stack def mod if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop modulo = a % b @stack.push(modulo) self end end # Duplicates the TOS (Top of Stack) def dup if @stack.size < 1 puts "Error: Stack underflow" # return error "Error" else a = @stack.pop @stack.push(a) @stack.push(a) self end end # Swaps the first two elements on the TOS def swap if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop @stack.push(b) @stack.push(a) self end end # Pops the TOS and discards it, def drop if @stack.size < 1 puts "Error: Empty Stack" # return error "Error" else @stack.pop self end end # Prints the stack without modifying it def dump print "[" print @stack.join(", ") puts "]" self end # Takes the second element from the stack and copies it to the TOS def over if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop @stack.push(a) @stack.push(b) @stack.push(a) self end end # Rotates the top three elements of the stack def rot if @stack.size < 3 puts "Error: Stack underflow" # return error "Error" else c = @stack.pop b = @stack.pop a = @stack.pop @stack.push(b) @stack.push(c) @stack.push(a) self end end # Pops the TOS and prints the value as an integer def dot if @stack.size < 1 puts "Error: Empty stack" # return error "Error" else a = @stack.pop print a print " " self end end # Pops the TOS and prints the value as an ASCII character def emit if @stack.size < 1 puts "Error: Stack underflow" # return error "Error" else a = @stack.pop print a.chr print " " self end end # Pop two elements from the TOS and # push -1 to the TOS if the first element is equal to the second element; # otherwise, 0 is pushed to the TOS, def eql if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop if a == b @stack.push(-1) else @stack.push(0) end self end end # Pop two elements from the TOS and # push -1 to the TOS if the first element is less than the second element; # otherwise, 0 is pushed to the TOS, def less if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop if a < b @stack.push(-1) else @stack.push(0) end self end end # Pop two elements from the TOS and # push -1 to the TOS if the first element is larger than the second element; # otherwise, 0 is pushed to the TOS, def larger if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop if a > b @stack.push(-1) else @stack.push(0) end self end end # Pop two elements from the TOS and # push back bitwise and of the first and second elements to the TOS def and if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop @stack.push(a & b) self end end # Pop two elements from the TOS and # push back bitwise or of the first and second elements to the TOS def or if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop @stack.push(a | b) self end end # Pop two elements from the TOS and # push back bitwise xor of the first and second elements to the TOS def xor if @stack.size < 2 puts "Error: Stack underflow" # return error "Error" else b = @stack.pop a = @stack.pop @stack.push(a ^ b) self end end # Pops a value from the TOS and pushes its bitwise negation (inversion) back def invert if @stack.size < 1 puts "Error: Stack underflow" # return error "Error" else a = @stack.pop @stack.push(~ a) self end end # multiplies the TOS with the cell width (which will always be 1, in this implementation) def cell if @stack.size < 1 puts "Error: Stack underflow" # return error "Error" else a = @stack.pop a = a * 1 @stack.push(a) self end end end a = Forth.new().eval

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text
×

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue