#!/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/python" PYTHON_CHECKER = "/usr/bin/pyflakes" PHP_INTERPRETER = "/usr/bin/php" 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" # 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 "#{param_name}: #{params[param_name]}" end # 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("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} 2> #{params[:message_file]}" system(command) when "c++" command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS} 2> #{params[:message_file]}" system(command) when "pas" command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS} > #{params[:message_file]}" system(command) 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]) do |line| 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} #{classname}.java 2> #{params[:message_file]}" system(command) 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]} 2> #{params[:message_file]}" if system(command) 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]} > #{params[:message_file]}" if system(command) #compile to python bytecode command = "#{PYTHON_INTERPRETER} -m py_compile #{params[:source_file]}" puts "compile: #{command}" system(command) puts "pwd: " + Dir.pwd Dir.new('.').each {|file| puts file} 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 when "php" command = "#{PHP_INTERPRETER} #{PHP_OPTIONS} #{params[:source_file]} 2> #{params[:message_file]}" if system(command) 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 else talk("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 "Compilation was successful!" else talk "ERROR: Something was wrong during the compilation!" end