#!/usr/bin/env ruby require 'fileutils' ############################## # # Standard Compile Script # # Supported compilers: # gcc, g++, and fpc. # ############################## def talk(str='') if ENV['TALKATIVE']!=nil puts str end if ENV['GRADER_LOGGING']!=nil log_fname = ENV['GRADER_LOGGING'] fp = File.open(log_fname,"a") fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}") fp.close end end C_COMPILER = "/usr/bin/gcc" CPLUSPLUS_COMPILER = "/usr/bin/g++" PASCAL_COMPILER = "/usr/bin/fpc" JAVA_COMPILER = "/usr/bin/javac" RUBY_INTERPRETER = "/usr/bin/ruby" PYTHON_INTERPRETER = "/usr/bin/python3" PYTHON_CHECKER = "/usr/bin/pyflakes" PHP_INTERPRETER = "/usr/bin/php" HASKELL_COMPILER = "/usr/bin/ghc" C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall" CPLUSPLUS_OPTIONS = "-O2 -s -std=c++11 -static -DCONTEST -lm -Wall" PASCAL_OPTIONS = "-O1 -XS -dCONTEST" JAVA_OPTIONS = "" PYTHON_OPTIONS = "" PHP_OPTIONS = "-l" HASKELL_OPTIONS = "" # Check for the correct number of arguments. Otherwise, print usage. if ARGV.length == 0 or ARGV.length > 4 puts "Usage: compile [] [] []" puts puts " is defaulted to \"source\"." puts " is defaulted to \"a.out\"." puts " is defaulted to \"compiler_message\"." puts exit(127) end PARAMS = { :source_file => [1,'source'], :output_file => [2,'a.out'], :message_file => [3,'compiler_message'] } params = {} params[:prog_lang] = ARGV[0] PARAMS.each_key do |param_name| index, default = PARAMS[param_name] if ARGV.length > index params[param_name] = ARGV[index] else params[param_name] = default end talk "COMPILE: param: #{param_name}: #{params[param_name]}" end talk "COMPILE: working dir = " + Dir.pwd # Remove any remaining output files or message files. if FileTest.exists? params[:output_file] FileUtils.rm(params[:output_file]) end if FileTest.exists? params[:message_file] FileUtils.rm(params[:message_file]) end # Check if the source file exists before attempt compiling. if !FileTest.exists? params[:source_file] talk("COMPILE: ERROR: The source file does not exist!") open(params[:message_file],"w") do |f| f.puts "ERROR: The source file did not exist." end exit(127) end if params[:prog_lang]=='cpp' params[:prog_lang] = 'c++' end # Compile. case params[:prog_lang] when "c" command = "#{C_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{C_OPTIONS}" talk "COMPILE: compiling command [#{command}]" system(command, err: params[:message_file]) when "c++" command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS}" talk "COMPILE: compiling command [#{command}]" system(command, err: params[:message_file]) when "pas" command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS}" talk "COMPILE: compiling command [#{command}]" system(command,out: params[:message_file]) FileUtils.mv("output", params[:output_file]) when "java" #rename the file to the public class name #get the class name classname = 'DUMMY' source = Array.new File.foreach(params[:source_file],'r:UTF-8') do |line| line.encode!('UTF-8','UTF-8',invalid: :replace, replace: '') md = /\s*public\s*class\s*(\w*)/.match(line) classname=md[1] if md source << line unless line =~ /\s*package\s*\w+\s*\;/ end File.open("#{classname}.java","w") do |file| source.each do |s| file.puts s end end #system("cp #{params[:source_file]} #{classname}.java") command = "#{JAVA_COMPILER} -encoding utf8 #{classname}.java" talk "COMPILE: compiling command [#{command}]" system(command, err: params[:message_file]) if File.exists?(classname + ".class") File.open(params[:output_file],"w") {|file| file.write("#{classname}")} end if classname == 'DUMMY' File.open(params[:message_file],"w") {|file| file.write("Cannot find any public class in the source code\n")} end when "ruby" command = "#{RUBY_INTERPRETER} -c #{params[:source_file]}" talk "COMPILE: compiling command [#{command}]" if system(command, err: params[:message_file]) File.open(params[:output_file],"w") do |out_file| out_file.puts "#!#{RUBY_INTERPRETER}" File.open(params[:source_file],"r").each do |line| out_file.print line end end File.chmod(0755, params[:output_file]) end when "python" #command = "#{PYTHON_CHECKER} #{params[:source_file]}" #if system(command, out: params[:message_file]) #compile to python bytecode command = "#{PYTHON_INTERPRETER} -c \"import py_compile; py_compile.compile('#{params[:source_file]}','#{params[:source_file]}c');\"" talk "COMPILE: compiling command [#{command}]" system(command, err: params[:message_file]) if FileTest.exists?("#{params[:source_file]}c") File.open(params[:output_file],"w") do |out_file| out_file.puts "#!#{PYTHON_INTERPRETER} #{params[:source_file]}c" end File.chmod(0755, params[:output_file]) FileUtils.cp("#{params[:source_file]}c",params[:output_file]) end #end when "php" command = "#{PHP_INTERPRETER} #{PHP_OPTIONS} #{params[:source_file]}" if system(command, err: params[:message_file]) File.open(params[:output_file],"w") do |out_file| out_file.puts "#!#{PHP_INTERPRETER}" File.open(params[:source_file],"r").each do |line| out_file.print line end end File.chmod(0755, params[:output_file]) end when "haskell" command = "#{HASKELL_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{HASKELL_OPTIONS}" talk "COMPILE: compiling command [#{command}]" system(command, err: params[:message_file]) else talk("COMPILE: ERROR: Invalid language specified!") open(params[:message_file],"w") do |f| f.puts "ERROR: Invalid language specified!" end exit(127) end # Report success or failure. if FileTest.exists? params[:output_file] talk "COMPILE: Compilation was successful!" else talk "COMPILE: ERROR: Something was wrong during the compilation!" end