def read_line( name: str, type_: Type, input_data: Input, iterator: IteratorName ) -> List[str]: """Generate the Lua code to read a line of given type""" assert type_.fits_in_one_line(input_data.structs) if type_.main == TypeEnum.LIST: assert type_.encapsulated is not None inner = iterator.new_it() iterator.pop_it() if type_.encapsulated.main == TypeEnum.CHAR: return [ "{} = {{}}".format(name), 'io.read():gsub(".",function({0}) table.insert({1}, {0}) end)'.format( inner, name ), ] assert type_.encapsulated.main == TypeEnum.INT return [ "{} = {{}}".format(name), 'for {} in string.gmatch(io.read(), "-?%d+") do'.format(inner), INDENTATION + "table.insert({}, tonumber({}))".format(name, inner), "end", ] if type_.main == TypeEnum.STRUCT: struct = input_data.get_struct(type_.struct_name) words = iterator.new_it() iterator.pop_it() pattern = " ".join( "(-?%d+)" if i.type.main == TypeEnum.INT else "(%S)" for i in struct.fields ) keys = ( '["{}"]'.format(i.name) if " " in i.name else i.name for i in struct.fields ) values = ( "tonumber({}[{}])".format(words, i + 1) if f.type.main == TypeEnum.INT else "{}[{}]".format(words, i + 1) for (i, f) in enumerate(struct.fields) ) return [ 'local {} = {{string.match(io.read(), "{}")}}'.format(words, pattern), "{} = {{{}}}".format( name, ", ".join(i + " = " + j for (i, j) in zip(keys, values)) ), ] return [ name + " = " + { TypeEnum.INT: "tonumber(io.read())", TypeEnum.CHAR: "io.read()", TypeEnum.STR: "io.read()", }[type_.main] ]
def read_lines( type_: Type, size: str, input_data: Input, iterator: IteratorName, style: FormatStyle = FormatStyle.DEFAULT, ) -> List[str]: """Generate the Ruby code to read the lines for a given type""" if type_.fits_in_one_line(input_data.structs, style): return [read_line(type_, input_data)] if type_.main == TypeEnum.LIST: assert type_.encapsulated is not None lines = read_lines(type_.encapsulated, var_name(type_.encapsulated.size), input_data, iterator) if len(lines) == 1: candidate = "Array.new({}) {{ {} }}".format(size, lines[0]) if len(candidate) <= 75: return [candidate] if lines[0][0] == "{": lines[0] = "Array.new({}) {{ {}".format(size, lines[0]) else: lines = ["Array.new({}) {{".format(size) ] + [INDENTATION + i for i in lines] if lines[-1][-1] == "}": lines[-1] += " }" else: lines.append("}") return lines assert type_.main == TypeEnum.STRUCT struct = input_data.get_struct(type_.struct_name) if struct.is_sized_struct(): inner = iterator.new_it() lines = read_lines(struct.fields[1].type, inner, input_data, iterator) iterator.pop_it() lines[0] = '"{}" => {}'.format(struct.fields[1].name, lines[0]) return ([ "(lambda {{ |{}| {{".format(inner), INDENTATION + '"{}" => {},'.format(struct.fields[0].name, inner), ] + [INDENTATION + i for i in lines] + ["} }).call(STDIN.gets.to_i)"]) fields = [] for i, field in enumerate(struct.fields): lines = read_lines(field.type, var_name(field.type.size), input_data, iterator) lines[0] = '{}"{}" => {}'.format(INDENTATION, field.name, lines[0]) if i != len(struct.fields) - 1: lines[-1] += "," fields.append(lines[0]) fields.extend([INDENTATION + i for i in lines[1:]]) return ["{"] + fields + ["}"]
def read_lines( var: Variable, size: str, input_data: Input, iterator: IteratorName ) -> List[str]: """Generate the Lua code to read the lines for a given type""" if var.fits_in_one_line(input_data.structs): return read_line(var.name, var.type, input_data, iterator) if var.type.main == TypeEnum.LIST: assert var.type.encapsulated is not None inner = iterator.new_it() lines = read_lines( Variable(f"{var.name}[{inner}]", "", var.type.encapsulated), var_name(var.type.encapsulated.size), input_data, iterator, ) iterator.pop_it() return ( [f"{var.name} = {{}}", f"for {inner} = 1, {size} do"] + [INDENTATION + i for i in lines] + ["end"] ) assert var.type.main == TypeEnum.STRUCT struct = input_data.get_struct(var.type.struct_name) lines = [var.name + " = {}"] for i, field in enumerate(struct.fields): f_size = var_name(field.type.size) if i == 1 and struct.is_sized_struct(): f_size = f'{var.name}["{struct.fields[0].name}"]' lines.extend( read_lines( Variable(f'{var.name}["{field.name}"]', "", field.type), f_size, input_data, iterator, ) ) return lines
class ParserC: """Create the C code to parse an input""" def __init__(self, input_data: Input) -> None: self.input = input_data self.includes = set() # type: Set[str] self.main = [] # type: List[str] self.method = [] # type: List[str] self.iterator = IteratorName([var.name for var in input_data.input]) self.endlines = [ (True, [], IntegerOrString.UNKNOWN) ] # type: List[Tuple[bool, List[int], IntegerOrString]] self.indentation = 4 def decl_new_scope(self, always_executed: bool) -> None: """Declare a new loop scope""" self.endlines.append((always_executed, [], IntegerOrString.UNKNOWN)) def decl_end_scope(self) -> None: """Declare the end of a loop scope, or the end of the program""" assert self.endlines if len(self.endlines) == 1: for line in reversed(self.endlines[0][1]): del self.main[line] self.endlines = [] else: if self.endlines[-1][2] == IntegerOrString.STRING: if self.endlines[-1][1]: self.endlines[-1][1].pop() # Need to keep this one self.endlines[-2][1].extend(self.endlines[-1][1]) self.endlines.pop() def decl_new_read_line(self, integer: IntegerOrString, indent: str) -> None: """Declare reading a new line, this will handle the line handling and the necessity to explicitly scan them""" if integer == IntegerOrString.INTEGER: index = len(self.endlines) - 1 if self.endlines[index][2] == IntegerOrString.UNKNOWN: self.endlines[index] = ( self.endlines[index][0], self.endlines[index][1], IntegerOrString.INTEGER, ) while index >= 0: for line in reversed(self.endlines[index][1]): del self.main[line] del self.endlines[index][1][:] if not self.endlines[index][0]: break index -= 1 elif integer == IntegerOrString.STRING: if self.endlines[-1][2] == IntegerOrString.UNKNOWN: self.endlines[-1] = ( self.endlines[-1][0], self.endlines[-1][1], IntegerOrString.STRING, ) for scope in self.endlines: del scope[1][:] self.endlines[-1][1].append(len(self.main)) self.main.append(indent + "getchar(); // \\n") def type_str(self, type_: Type) -> str: """Return the C name for a type""" if type_.main == TypeEnum.INT: return "int" if type_.main == TypeEnum.STR: return "char*" if type_.main == TypeEnum.CHAR: return "char" if type_.main == TypeEnum.STRUCT: return "struct " + struct_name(type_.struct_name) assert type_.main == TypeEnum.LIST assert type_.encapsulated return self.type_str(type_.encapsulated) + "*" def read_line(self, name: str, type_: Type, size: str, indent_lvl: int) -> None: """Read an entire line and store it into the right place(s)""" assert type_.fits_in_one_line(self.input.structs) indent = " " * (self.indentation * indent_lvl) self.includes.add("stdio.h") if type_.main == TypeEnum.INT: self.main.append(indent + 'scanf("%d", &{});'.format(name)) self.decl_new_read_line(IntegerOrString.INTEGER, indent) elif type_.main == TypeEnum.CHAR: if "." in name or "[" in name: self.main.append(indent + "{} = getchar();".format(name)) self.decl_new_read_line(IntegerOrString.STRING, indent) elif type_.main == TypeEnum.STR: self.main.append(indent + 'scanf("%[^\\n]", {});'.format(name)) self.decl_new_read_line(IntegerOrString.STRING, indent) elif type_.main == TypeEnum.LIST: assert type_.encapsulated is not None if type_.encapsulated.main == TypeEnum.CHAR: self.main.append( indent + "fgets({}, {} + 1, stdin);".format(name, size)) self.decl_new_read_line(IntegerOrString.STRING, indent) else: assert type_.encapsulated.main == TypeEnum.INT index = self.iterator.new_it() self.main.append( indent + "for (int {0} = 0; {0} < {1}; ++{0})".format(index, size)) self.main.append(" " * self.indentation + indent + 'scanf("%d", &{}[{}]);'.format(name, index)) self.decl_new_read_line( IntegerOrString.UNKNOWN if type_.can_be_empty else IntegerOrString.INTEGER, indent, ) self.iterator.pop_it() else: assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) self.main.append(indent + 'scanf("{}", {});'.format( " ".join("%c" if i.type.main == TypeEnum.CHAR else "%d" for i in struct.fields), ", ".join("&" + name + "." + var_name(i.name) for i in struct.fields), )) self.decl_new_read_line( IntegerOrString.STRING if struct.fields[0].type.main == TypeEnum.CHAR else IntegerOrString.INTEGER, indent, ) def read_lines(self, name: str, type_: Type, size: str, indent_lvl: int = 0) -> None: """Read one or several lines and store them into the right place(s)""" not_initialized = "." in name or "[" in name if type_.main == TypeEnum.LIST and not_initialized: assert type_.encapsulated is not None self.includes.add("stdlib.h") array_size = ("({} + 1)".format(size) if type_.main == TypeEnum.CHAR else size) self.main.append( "{0}{1} = ({3}*)malloc({2} * sizeof({3}));".format( " " * self.indentation * indent_lvl, name, array_size, self.type_str(type_.encapsulated), )) elif type_.main == TypeEnum.STR and not_initialized: self.includes.add("stdlib.h") self.main.append( "{}{} = (char*)malloc(({} + 1) * sizeof(char));".format( " " * self.indentation * indent_lvl, name, size)) if type_.fits_in_one_line(self.input.structs): self.read_line(name, type_, size, indent_lvl) else: if type_.main == TypeEnum.STRUCT: struct = self.input.get_struct(type_.struct_name) for f_name, f_type, f_size in struct.fields_name_type_size( "{}.{{}}".format(name), var_name): self.read_lines(f_name, f_type, f_size, indent_lvl) else: assert type_.main == TypeEnum.LIST assert type_.encapsulated is not None index = self.iterator.new_it() self.decl_new_scope(not type_.can_be_empty) self.main.append( "{0}for (int {1} = 0; {1} < {2}; ++{1}) {{".format( " " * self.indentation * indent_lvl, index, size)) self.read_lines( "{}[{}]".format(name, index), type_.encapsulated, var_name(type_.encapsulated.size), indent_lvl + 1, ) self.main.append(" " * self.indentation * indent_lvl + "}") self.iterator.pop_it() self.decl_end_scope() def read_var(self, var: Variable) -> None: """Read a variable""" init = "" if var.type.main == TypeEnum.CHAR: self.includes.add("stdio.h") init = " = getchar()" elif var.type.main == TypeEnum.STR: self.includes.add("stdlib.h") init = " = (char*)malloc(({} + 1) * sizeof(char))".format( var_name(var.type.size)) elif var.type.main == TypeEnum.LIST: assert var.type.encapsulated is not None self.includes.add("stdlib.h") array_size = ("({} + 1)".format(var_name(var.type.size)) if var.type.encapsulated.main == TypeEnum.CHAR else var_name(var.type.size)) init = " = ({1}*)malloc({0} * sizeof({1}))".format( array_size, self.type_str(var.type.encapsulated)) self.main.append("{} {}{};".format( self.type_str(var.type), var_name(var.name), init, )) self.read_lines(var_name(var.name), var.type, var_name(var.type.size)) def call(self, reprint: bool) -> None: """Declare and call the function take all inputs in arguments""" name = var_name(self.input.name) arguments = [] for arg in self.input.input: arg_name = var_name(arg.name) self.method.append("/// \\param {} {}".format( arg_name, arg.comment)) arguments.append("{} {}".format(self.type_str(arg.type), arg_name)) self.method.append("void {}({}) {{".format(name, ", ".join(arguments))) if reprint: for var in self.input.input: self.print_lines( Variable(var_name(var.name), "", var.type, var.format_style), var_name(var.type.size), 1, ) else: self.method.extend([ " " * self.indentation + i for i in textwrap.wrap("/* TODO " + self.input.output + " */", 79 - self.indentation) ]) self.method.append("}") def print_line(self, var: Variable, size: str, indent_lvl: int) -> None: """Print the content of a var that holds in one line""" assert var.type.fits_in_one_line(self.input.structs) indent = " " * (self.indentation * indent_lvl) newline = " " if var.format_style == FormatStyle.NO_ENDLINE else r"\n" if var.type.main == TypeEnum.INT: self.method.append(indent + f'printf("%d{newline}", {var.name});') elif var.type.main == TypeEnum.CHAR: self.method.append(indent + f'printf("%c{newline}", {var.name});') elif var.type.main == TypeEnum.STR: self.method.append(indent + f'printf("%s{newline}", {var.name});') elif var.type.main == TypeEnum.LIST: assert var.type.encapsulated is not None if var.type.encapsulated.main == TypeEnum.CHAR: self.method.append(indent + f'printf("%s{newline}", {var.name});') else: index = self.iterator.new_it() self.method.append( indent + "for (int {0} = 0; {0} < {1}; ++{0})".format(index, size)) self.method.append( " " * self.indentation + indent + "printf(\"%d%c\", {0}[{1}], {1} < {2} - 1 ? ' ' : '\\n');". format(var.name, index, size)) self.method.append(indent + "if ({} == 0) putchar('\\n');".format(size)) self.iterator.pop_it() else: assert var.type.main == TypeEnum.STRUCT struct = self.input.get_struct(var.type.struct_name) self.method.append(indent + 'printf("{}\\n", {});'.format( " ".join("%c" if i.type.main == TypeEnum.CHAR else "%d" for i in struct.fields), ", ".join(var.name + "." + var_name(i.name) for i in struct.fields), )) def print_lines(self, var: Variable, size: str, indent_lvl: int) -> None: """Print the content of a var that holds in one or more lines""" if var.fits_in_one_line(self.input.structs): self.print_line(var, size, indent_lvl) else: if var.type.main == TypeEnum.STRUCT: struct = self.input.get_struct(var.type.struct_name) struct = self.input.get_struct(var.type.struct_name) for f_name, f_type, f_size in struct.fields_name_type_size( f"{var.name}.{{}}", var_name): self.print_lines(Variable(f_name, "", f_type), f_size, indent_lvl) else: assert var.type.main == TypeEnum.LIST assert var.type.encapsulated is not None index = self.iterator.new_it() self.method.append( "{0}for (int {1} = 0; {1} < {2}; ++{1}) {{".format( " " * self.indentation * indent_lvl, index, size)) self.print_lines( Variable(f"{var.name}[{index}]", "", var.type.encapsulated), var_name(var.type.encapsulated.size), indent_lvl + 1, ) self.method.append(" " * self.indentation * indent_lvl + "}") self.iterator.pop_it() def content(self) -> str: """Return the parser content""" output = "" for include in sorted(self.includes): output += "#include <{}>\n".format(include) if self.includes: output += "\n" for struct in self.input.structs: output += "/// {}\n".format(struct.comment) output += "struct {} {{\n".format(struct_name(struct.name)) for field in struct.fields: output += " " * self.indentation + "{} {}; ///< {}\n".format( self.type_str(field.type), var_name(field.name), field.comment) output += "};\n\n" for line in self.method: output += line + "\n" if self.method: output += "\n" output += "int main() {\n" for line in self.main: output += " " * self.indentation + line + "\n" output += " " * self.indentation + "{}({});\n".format( var_name(self.input.name), ", ".join([var_name(i.name) for i in self.input.input]), ) output += "\n" + " " * self.indentation + "return 0;\n}\n" return output
class ParserCS: """Create the C# code to parse an input""" def __init__(self, input_data: Input) -> None: self.input = input_data existing_names = [var.name for var in input_data.input] self.iterator = IteratorName(existing_names) self.words = WordsName(existing_names, cs_mode=True) def read_line(self, decl: bool, name: str, type_: Type, indent_lvl: int) -> List[str]: """Read an entire line and store it into the right place(s)""" assert type_.fits_in_one_line(self.input.structs) indent = INDENTATION * indent_lvl if type_.main == TypeEnum.STRUCT: struct = self.input.get_struct(type_.struct_name) s_name = pascal_name(struct.name) + " " words = self.words.next_name() lines = [ indent + "string[] {} = Console.ReadLine().Split(' ');".format(words) ] return lines + [ "{}{}{} = new {}{{{}}};".format( indent, s_name if decl else "", name, s_name, ", ".join("{} = {}".format( var_name(f.name), "int.Parse({}[{}])".format(words, i) if f.type.main == TypeEnum.INT else "{}[{}][0]".format(words, i), ) for i, f in enumerate(struct.fields)), ) ] type_decl = (type_str(type_) + " ") if decl else "" command = "" if type_.main == TypeEnum.INT: command = "int.Parse(Console.ReadLine())" elif type_.main == TypeEnum.CHAR: command = "Console.ReadLine()[0]" elif type_.main == TypeEnum.STR: command = "Console.ReadLine()" else: assert type_.main == TypeEnum.LIST assert type_.encapsulated is not None if type_.encapsulated.main == TypeEnum.CHAR: command = "Console.ReadLine().ToCharArray()" else: assert type_.encapsulated.main == TypeEnum.INT command = ( "Array.ConvertAll(Console.ReadLine().Split({}), " "int.Parse)" ).format( "new char[] {' '}, StringSplitOptions.RemoveEmptyEntries" if type_.can_be_empty else "' '") assert command return ["{}{}{} = {};".format(indent, type_decl, name, command)] def read_lines( self, decl: bool, name: str, type_: Type, size: str, indent_lvl: int, style: FormatStyle = FormatStyle.DEFAULT, ) -> List[str]: # pylint: disable=too-many-arguments # pylint: disable=too-many-locals """Read one or several lines and store them into the right place(s)""" if type_.fits_in_one_line(self.input.structs, style): return self.read_line(decl, name, type_, indent_lvl) indent = INDENTATION * indent_lvl if type_.main == TypeEnum.STRUCT: lines = [] if decl: lines.append("{}{} {};".format(indent, pascal_name(type_.struct_name), name)) struct = self.input.get_struct(type_.struct_name) for f_name, f_type, f_size in struct.fields_name_type_size( "{}.{{}}".format(name), var_name): lines.extend( self.read_lines(False, f_name, f_type, f_size, indent_lvl)) return lines assert type_.main == TypeEnum.LIST assert type_.encapsulated is not None far_inner_type = type_.encapsulated list_suffix = "" while far_inner_type.main == TypeEnum.LIST: assert far_inner_type.encapsulated is not None far_inner_type = far_inner_type.encapsulated list_suffix += "[]" lines = [ "{}{}{} = new {}[{}]{};".format( indent, (type_str(type_) + " ") if decl else "", name, type_str(far_inner_type), size, list_suffix, ) ] index = self.iterator.new_it() self.words.push_scope() lines.append("{0}for (int {1} = 0; {1} < {2}; ++{1})".format( indent, index, size)) lines.append(indent + "{") lines.extend( self.read_lines( False, "{}[{}]".format(name, index), type_.encapsulated, var_name(type_.encapsulated.size), indent_lvl + 1, )) self.words.pop_scope() self.iterator.pop_it() return lines + [indent + "}"] def call(self, reprint: bool) -> List[str]: """Declare and call the function take all inputs in arguments""" lines = [] arguments = [] for arg in self.input.input: arg_name = var_name(arg.name) lines.append(INDENTATION + "/// \\param {} {}".format(arg_name, arg.comment)) arguments.append("{} {}".format(type_str(arg.type), arg_name)) lines.append("{0}static void {1}({2})\n{0}{{".format( INDENTATION, pascal_name(self.input.name), ", ".join(arguments))) if reprint: for variables in self.input.get_all_vars(): if len(variables) == 1: var = variables[0] lines.extend( self.print_lines(var_name(var.name), var.type, 2, var.format_style)) else: fmt = " ".join(f"{{{i}}}" for i in range(len(variables))) lines.append( INDENTATION * 2 + f'Console.WriteLine("{fmt}", ' + f"{', '.join(var_name(i.name) for i in variables)});") else: lines.extend([ 2 * INDENTATION + i for i in textwrap.wrap( "/* TODO " + self.input.output + " */", 79 - 2 * len(INDENTATION), ) ]) return lines + [INDENTATION + "}"] def print_line(self, name: str, type_: Type) -> str: """Print the content of a var that holds in one line""" assert type_.fits_in_one_line(self.input.structs) if type_.main in (TypeEnum.INT, TypeEnum.CHAR, TypeEnum.STR): return "Console.WriteLine({});".format(name) if type_.main == TypeEnum.LIST: assert type_.encapsulated is not None if type_.encapsulated.main == TypeEnum.CHAR: return "Console.WriteLine(new string({}));".format(name) assert type_.encapsulated.main == TypeEnum.INT return 'Console.WriteLine(String.Join(" ", {}));'.format(name) assert type_.main == TypeEnum.STRUCT fields = self.input.get_struct(type_.struct_name).fields return 'Console.WriteLine("{}", {});'.format( " ".join("{{{}}}".format(i) for i in range(len(fields))), ", ".join("{}.{}".format(name, var_name(f.name)) for f in fields), ) def print_lines( self, name: str, type_: Type, indent_lvl: int, style: FormatStyle = FormatStyle.DEFAULT, ) -> List[str]: """Print the content of a var that holds in one or more lines""" if type_.fits_in_one_line(self.input.structs, style): return [INDENTATION * indent_lvl + self.print_line(name, type_)] if type_.main == TypeEnum.STRUCT: struct = self.input.get_struct(type_.struct_name) lines = [] for field in struct.fields: lines.extend( self.print_lines( "{}.{}".format(name, var_name(field.name)), field.type, indent_lvl, )) return lines assert type_.main == TypeEnum.LIST assert type_.encapsulated is not None index = self.iterator.new_it() self.words.push_scope() lines = [ "{}foreach ({} {} in {})".format(INDENTATION * indent_lvl, type_str(type_.encapsulated), index, name) ] lines.append(INDENTATION * indent_lvl + "{") lines.extend( self.print_lines(index, type_.encapsulated, indent_lvl + 1)) lines.append(INDENTATION * indent_lvl + "}") self.words.pop_scope() self.iterator.pop_it() return lines def content(self, reprint: bool) -> str: """Return the parser content""" output = "using System;\n\n" for struct in self.input.structs: output += "/// {}\n".format(struct.comment) output += "struct {}\n{{\n".format(pascal_name(struct.name)) for field in struct.fields: output += INDENTATION + "public {} {}; //!< {}\n".format( type_str(field.type), var_name(field.name), field.comment) output += "}\n\n" output += "class Program\n{\n" output += "\n".join(self.call(reprint)) + "\n" output += "\n{0}static void Main()\n{0}{{\n".format(INDENTATION) for variables in self.input.get_all_vars(): if len(variables) == 1: var = variables[0] for line in self.read_lines( True, var_name(var.name), var.type, var_name(var.type.size), 2, var.format_style, ): output += line + "\n" else: words = self.words.next_name() output += (f"{INDENTATION * 2}string[] {words}" " = Console.ReadLine().Split(' ');\n") for i, var in enumerate(variables): assert var.type.main == TypeEnum.INT output += ( INDENTATION * 2 + f"int {var_name(var.name)} = int.Parse({words}[{i}]);\n" ) args = (var_name(var.name) for var in self.input.input) output += "\n{}{}({});\n".format(INDENTATION * 2, pascal_name(self.input.name), ", ".join(args)) output += INDENTATION + "}\n}\n" return output
class ParserCpp: """Create the C++ code to parse an input""" def __init__(self, input_data: Input) -> None: self.input = input_data self.includes = set() # type: Set[str] self.main = [] # type: List[str] self.method = [] # type: List[str] self.iterator = IteratorName([var.name for var in input_data.input]) self.indent_lvl = 0 self.indentation = 4 def type_str(self, type_: Type) -> str: """Return the C++ name for a type""" if type_.main == TypeEnum.INT: return "int" if type_.main == TypeEnum.STR: self.includes.add("string") return "std::string" if type_.main == TypeEnum.CHAR: return "char" if type_.main == TypeEnum.STRUCT: return struct_name(type_.struct_name) assert type_.encapsulated assert type_.main == TypeEnum.LIST self.includes.add("vector") return "std::vector<{}>".format(self.type_str(type_.encapsulated)) def read_line(self, name: str, type_: Type, size: str) -> None: """Read an entire line and store it into the right place(s)""" assert type_.fits_in_one_line(self.input.structs) indent = " " * (self.indentation * self.indent_lvl) self.includes.add("iostream") if type_.main in (TypeEnum.INT, TypeEnum.CHAR): self.main.append(indent + "std::cin >> {};".format(name)) elif type_.main == TypeEnum.STR: self.includes.add("string") self.includes.add("istream") if type_.can_be_empty: self.main.append(indent + "if ({} > 0)".format(size)) self.main.append( indent + " " * (self.indentation if type_.can_be_empty else 0) + "std::getline(std::cin >> std::ws, {});".format(name) ) elif type_.main == TypeEnum.LIST: assert type_.encapsulated is not None inner_name = self.iterator.new_it() self.main.append( indent + "for ({}& {} : {})".format( self.type_str(type_.encapsulated), inner_name, name ) ) self.main.append( " " * self.indentation + indent + "std::cin >> {};".format(inner_name) ) self.iterator.pop_it() else: assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) self.main.append( indent + "std::cin >> {};".format( " >> ".join( "{}.{}".format(name, var_name(x.name)) for x in struct.fields ) ) ) def read_lines( self, name: str, type_: Type, size: str, already_resized: bool = False, ) -> None: """Read one or several lines and store them into the right place(s)""" if type_.main == TypeEnum.LIST and not already_resized: self.main.append( "{}{}.resize({});".format( " " * self.indentation * self.indent_lvl, name, size ) ) if type_.fits_in_one_line(self.input.structs): self.read_line(name, type_, size) else: if type_.main == TypeEnum.STRUCT: struct = self.input.get_struct(type_.struct_name) for f_name, f_type, f_size in struct.fields_name_type_size( "{}.{{}}".format(name), var_name ): self.read_lines(f_name, f_type, f_size) else: assert type_.main == TypeEnum.LIST assert type_.encapsulated is not None inner_name = self.iterator.new_it() self.main.append( "{}for ({}& {} : {}) {{".format( " " * self.indentation * self.indent_lvl, self.type_str(type_.encapsulated), inner_name, name, ) ) self.indent_lvl += 1 self.read_lines( inner_name, type_.encapsulated, var_name(type_.encapsulated.size), ) self.indent_lvl -= 1 self.main.append(" " * self.indentation * self.indent_lvl + "}") self.iterator.pop_it() def read_var(self, var: Variable) -> None: """Read a variable""" size = "" if var.type.main == TypeEnum.LIST: try: size = "({})".format(int(var.type.size)) except ValueError: size = "({})".format(var_name(var.type.size)) self.main.append( "{} {}{}; ///< {}".format( self.type_str(var.type), var_name(var.name), size, var.comment ) ) self.read_lines( var_name(var.name), var.type, var_name(var.type.size), already_resized=True ) def call(self, reprint: bool) -> None: """Declare and call the function take all inputs in arguments""" name = var_name(self.input.name) arguments = [] for arg in self.input.input: arg_name = var_name(arg.name) self.method.append("/// \\param {} {}".format(arg_name, arg.comment)) if arg.type.main in (TypeEnum.STR, TypeEnum.LIST, TypeEnum.STRUCT): arguments.append( "const {}& {}".format(self.type_str(arg.type), arg_name) ) else: arguments.append("{} {}".format(self.type_str(arg.type), arg_name)) self.method.append("void {}({}) {{".format(name, ", ".join(arguments))) if reprint: for var in self.input.input: self.print_lines(var_name(var.name), var.type, 1, var.format_style) else: self.method.extend( [ " " * self.indentation + i for i in textwrap.wrap( "/* TODO " + self.input.output + " */", 79 - self.indentation ) ] ) self.method.append("}") def print_line( self, name: str, type_: Type, indent_lvl: int, style: FormatStyle ) -> None: """Print the content of a var that holds in one line""" assert type_.fits_in_one_line(self.input.structs, style) indent = " " * (self.indentation * indent_lvl) endl = '" "' if style == FormatStyle.NO_ENDLINE else "std::endl" if type_.main in (TypeEnum.INT, TypeEnum.CHAR, TypeEnum.STR): self.method.append(f"{indent}std::cout << {name} << {endl};") elif type_.main == TypeEnum.LIST: assert type_.encapsulated is not None inner_name = self.iterator.new_it() self.method.append( indent + "for (size_t {0} = 0; {0} < {1}.size(); ++{0})".format( inner_name, name ) ) self.method.append( " " * self.indentation + indent + "std::cout << " + '{0}[{1}] << ({1} < {0}.size() - 1 ? "{2}" : "\\n");'.format( name, inner_name, "" if type_.encapsulated.main == TypeEnum.CHAR else " ", ) ) self.method.append( indent + "if ({}.size() == 0) std::cout << std::endl;".format(name) ) self.iterator.pop_it() else: assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) self.method.append( indent + "std::cout << {} << std::endl;".format( " << ' ' << ".join( "{}.{}".format(name, var_name(x.name)) for x in struct.fields ) ) ) def print_lines( self, name: str, type_: Type, indent_lvl: int, style: FormatStyle = FormatStyle.DEFAULT, ) -> None: """Print the content of a var that holds in one or more lines""" if type_.fits_in_one_line(self.input.structs, style): self.print_line(name, type_, indent_lvl, style) else: if type_.main == TypeEnum.STRUCT: for field in self.input.get_struct(type_.struct_name).fields: self.print_lines( "{}.{}".format(name, var_name(field.name)), field.type, indent_lvl, ) else: assert type_.main == TypeEnum.LIST assert type_.encapsulated is not None inner_name = self.iterator.new_it() self.method.append( "{}for (const {}& {} : {}) {{".format( " " * self.indentation * indent_lvl, self.type_str(type_.encapsulated), inner_name, name, ) ) self.print_lines(inner_name, type_.encapsulated, indent_lvl + 1) self.method.append(" " * self.indentation * indent_lvl + "}") self.iterator.pop_it() def content(self) -> str: """Return the parser content""" output = "" for include in sorted(self.includes): output += "#include <{}>\n".format(include) if self.includes: output += "\n" for struct in self.input.structs: output += "/// {}\n".format(struct.comment) output += "struct {} {{\n".format(struct_name(struct.name)) for field in struct.fields: output += " " * self.indentation + "{} {}; ///< {}\n".format( self.type_str(field.type), var_name(field.name), field.comment ) output += "};\n\n" for line in self.method: output += line + "\n" if self.method: output += "\n" output += "int main() {\n" for line in self.main: output += " " * self.indentation + line + "\n" output += " " * self.indentation + "{}({});\n".format( var_name(self.input.name), ", ".join([var_name(i.name) for i in self.input.input]), ) output += "}\n" return output
class ParserGo: """Create the Go code to parse an input""" def __init__(self, input_data: Input) -> None: self.input = input_data self.imports = set(["bufio", "os"]) self.iterator = IteratorName([var.name for var in input_data.input]) def read_line(self, name: str, size: str, type_: Type) -> List[str]: """Read an entire line and store it into the right place(s)""" # pylint: disable=too-many-return-statements assert type_.fits_in_one_line(self.input.structs) if type_.main == TypeEnum.INT: self.imports.add("strconv") return [ "scanner.Scan()", f"{name}, _ = strconv.Atoi(scanner.Text())", ] if type_.main == TypeEnum.CHAR: return ["scanner.Scan()", f"{name} = scanner.Text()[0]"] if type_.main == TypeEnum.STR: return [ "scanner.Scan()", f"{name} = scanner.Text()", ] if type_.main == TypeEnum.LIST: assert type_.encapsulated is not None if type_.encapsulated.main == TypeEnum.CHAR: return [ "scanner.Scan()", f"{name} = scanner.Bytes()", ] inner_name = self.iterator.new_it() self.imports.add("strings") self.imports.add("strconv") lines = [ "scanner.Scan()", f"for {inner_name}, {inner_name}Value " + f':= range strings.SplitN(scanner.Text(), " ", {size}) {{', ] lines.append( INDENTATION + f"{name}[{inner_name}], _ = strconv.Atoi({inner_name}Value)" ) self.iterator.pop_it() return lines + ["}"] assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) self.imports.add("fmt") return [ "scanner.Scan()", 'fmt.Sscanf(scanner.Text(), "{}", {})'.format( " ".join( "%d" if f.type.main == TypeEnum.INT else "%c" for f in struct.fields ), ", ".join( "&{}.{}".format(name, var_name(f.name)) for f in struct.fields ), ), ] def read_lines( self, var: Variable, size: str, already_allocated: bool = False, ) -> List[str]: """Read one or several lines and store them into the right place(s)""" lines = [] if var.type.main == TypeEnum.LIST and not already_allocated: lines.append(f"{var.name} = make({type_str(var.type)}, {size})") if var.fits_in_one_line(self.input.structs): return lines + self.read_line(var.name, size, var.type) if var.type.main == TypeEnum.STRUCT: struct = self.input.get_struct(var.type.struct_name) for f_name, f_type, f_size in struct.fields_name_type_size( var.name + ".{}", var_name ): lines.extend(self.read_lines(Variable(f_name, "", f_type), f_size)) return lines assert var.type.main == TypeEnum.LIST assert var.type.encapsulated is not None inner_name = self.iterator.new_it() lines.append(f"for {inner_name} := range {var.name} {{") lines.extend( INDENTATION + i for i in self.read_lines( Variable(f"{var.name}[{inner_name}]", "", var.type.encapsulated), var_name(var.type.encapsulated.size), ) ) lines.append("}") self.iterator.pop_it() return lines def read_var(self, var: Variable) -> List[str]: """Read a variable""" make = False if var.type.main == TypeEnum.LIST: assert var.type.encapsulated is not None if var.type.encapsulated.main != TypeEnum.CHAR: make = True lines = [] if make: lines.append( "{} := make({}, {})".format( var_name(var.name), type_str(var.type), var_name(var.type.size) ) ) else: lines.append("var {} {}".format(var_name(var.name), type_str(var.type))) lines.extend( self.read_lines( Variable(var_name(var.name), "", var.type, var.format_style), var_name(var.type.size), already_allocated=True, ) ) return lines def call(self, reprint: bool) -> List[str]: """Declare and call the function take all inputs in arguments""" lines = [] name = var_name(self.input.name) arguments = [] for arg in self.input.input: arg_name = var_name(arg.name) lines.append("// {}: {}".format(arg_name, arg.comment)) arguments.append("{} {}".format(arg_name, type_str(arg.type))) lines.append("func {}({}) {{".format(name, ", ".join(arguments))) if reprint: for var in self.input.input: lines.extend( self.print_lines(var_name(var.name), var.type, 1, var.format_style) ) else: lines.extend( [ INDENTATION + i for i in textwrap.wrap( "/* TODO " + self.input.output + " */", 79 - len(INDENTATION) ) ] ) return lines + ["}"] def print_line( self, name: str, type_: Type, indent_lvl: int, style: FormatStyle ) -> List[str]: """Print the content of a var that holds in one line""" assert type_.fits_in_one_line(self.input.structs, style) indent = INDENTATION * indent_lvl self.imports.add("fmt") if type_.main in (TypeEnum.INT, TypeEnum.STR): return [ indent + ( f'fmt.Print({name}, " ");' if style == FormatStyle.NO_ENDLINE else f"fmt.Println({name});" ) ] if type_.main == TypeEnum.CHAR: return [indent + 'fmt.Printf("%c\\n", {});'.format(name)] if type_.main == TypeEnum.LIST: assert type_.encapsulated is not None if type_.encapsulated.main == TypeEnum.CHAR: return [indent + "fmt.Println(string({}));".format(name)] index = self.iterator.new_it() lines = [ indent + "for {} := range {} {{".format(index, name), indent + INDENTATION + "fmt.Print({}[{}])".format(name, index), ] lines.extend( [ indent + INDENTATION + "if {} < len({}) - 1 {{".format(index, name), indent + 2 * INDENTATION + 'fmt.Print(" ")', indent + INDENTATION + "}", ] ) self.iterator.pop_it() return lines + [indent + "}", indent + "fmt.Println()"] assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) return [ indent + 'fmt.Printf("{}\\n", {})'.format( " ".join( "%d" if x.type.main == TypeEnum.INT else "%c" for x in struct.fields ), ", ".join( "{}.{}".format(name, var_name(x.name)) for x in struct.fields ), ) ] def print_lines( self, name: str, type_: Type, indent_lvl: int, style: FormatStyle = FormatStyle.DEFAULT, ) -> List[str]: """Print the content of a var that holds in one or more lines""" if type_.fits_in_one_line(self.input.structs, style): return self.print_line(name, type_, indent_lvl, style) if type_.main == TypeEnum.STRUCT: lines = [] for field in self.input.get_struct(type_.struct_name).fields: lines.extend( self.print_lines( "{}.{}".format(name, var_name(field.name)), field.type, indent_lvl, ) ) return lines assert type_.main == TypeEnum.LIST assert type_.encapsulated is not None inner_name = self.iterator.new_it() lines = [ "{}for _, {} := range {} {{".format( INDENTATION * indent_lvl, inner_name, name ) ] lines.extend(self.print_lines(inner_name, type_.encapsulated, indent_lvl + 1)) lines.append(INDENTATION * indent_lvl + "}") self.iterator.pop_it() return lines def content(self, reprint: bool) -> str: """Return the parser content""" output = "" for struct in self.input.structs: output += "// {}\n".format(struct.comment) output += "type {} struct {{\n".format(struct_name(struct.name)) for field in struct.fields: output += INDENTATION + "{} {} // {}\n".format( var_name(field.name), type_str(field.type), field.comment ) output += "}\n\n" output += "\n".join(self.call(reprint)) + "\n\n" output += "func main() {\n" output += INDENTATION + "scanner := bufio.NewScanner(os.Stdin)\n" max_line_length = max( max_size(i.type, i.constraints, self.input, i.format_style) for i in self.input.input ) if max_line_length > 64 * 1024: # bufio.MaxScanTokenSize output += INDENTATION + ( "scanner.Buffer(make([]byte, 0, " "64 * 1024), {})\n" ).format(max_line_length + 1) for variables in self.input.get_all_vars(): if len(variables) == 1: for line in self.read_var(variables[0]): output += INDENTATION + line + "\n" else: assert all(var.type.main == TypeEnum.INT for var in variables) output += ( INDENTATION + f"var {', '.join(var_name(i.name) for i in variables)} int\n" ) self.imports.add("fmt") output += INDENTATION + "scanner.Scan()\n" output += ( INDENTATION + 'fmt.Sscanf(scanner.Text(), "{}", {});\n'.format( " ".join(["%d"] * len(variables)), ", ".join("&" + var_name(i.name) for i in variables), ) ) output += INDENTATION + "{}({});\n".format( var_name(self.input.name), ", ".join([var_name(i.name) for i in self.input.input]), ) output += "}\n" return ( "package main\n\n" + "\n".join('import "{}"'.format(i) for i in sorted(self.imports)) + "\n\n" + output )
class ParserJava: """Create the Java code to parse an input""" def __init__(self, input_data: Input) -> None: self.input = input_data self.imports = set( ["java.io.BufferedReader", "java.io.InputStreamReader"]) existing_names = [var.name for var in input_data.input ] + [var_name(input_data.name)] self.iterator = IteratorName(existing_names) self.words = WordsName(existing_names) def read_line(self, decl: bool, name: str, type_: Type, indent_lvl: int) -> List[str]: """Read an entire line and store it into the right place(s)""" assert type_.fits_in_one_line(self.input.structs) indent = INDENTATION * indent_lvl if type_.main == TypeEnum.STRUCT: struct = self.input.get_struct(type_.struct_name) words = self.words.next_name() lines = [ indent + f'String[] {words} = reader.readLine().split(" ");' ] lines.append(indent + "{}{} = new {}();".format( class_name(type_.struct_name) + " " if decl else "", name, class_name(type_.struct_name), )) lines.extend("{}{}.{} = {};".format( indent, name, var_name(f.name), f"Integer.parseInt({words}[{i}])" if f.type.main == TypeEnum.INT else f"{words}[{i}].charAt(0)", ) for i, f in enumerate(struct.fields)) return lines type_decl = (type_str(type_) + " ") if decl else "" command = "" if type_.main == TypeEnum.INT: command = "Integer.parseInt(reader.readLine())" elif type_.main == TypeEnum.CHAR: command = "reader.readLine().charAt(0)" elif type_.main == TypeEnum.STR: command = "reader.readLine()" else: assert type_.main == TypeEnum.LIST assert type_.encapsulated is not None if type_.encapsulated.main == TypeEnum.CHAR: command = "reader.readLine().toCharArray()" else: assert type_.encapsulated.main == TypeEnum.INT self.imports.add("java.util.Arrays") command = ('Arrays.stream(reader.readLine().split(" ")).{}' "mapToInt(Integer::parseInt).toArray()" ).format("filter(x -> !x.isEmpty())." if type_. can_be_empty else "") assert command return ["{}{}{} = {};".format(indent, type_decl, name, command)] def read_lines(self, decl: bool, var: Variable, size: str, indent_lvl: int) -> List[str]: # pylint: disable=too-many-arguments # pylint: disable=too-many-locals """Read one or several lines and store them into the right place(s)""" if var.fits_in_one_line(self.input.structs): return self.read_line(decl, var.name, var.type, indent_lvl) indent = INDENTATION * indent_lvl if var.type.main == TypeEnum.STRUCT: lines = [ indent + "{}{} = new {}();".format( class_name(var.type.struct_name) + " " if decl else "", var.name, class_name(var.type.struct_name), ) ] struct = self.input.get_struct(var.type.struct_name) for f_name, f_type, f_size in struct.fields_name_type_size( f"{var.name}.{{}}", var_name): lines.extend( self.read_lines(False, Variable(f_name, "", f_type), f_size, indent_lvl)) return lines assert var.type.main == TypeEnum.LIST assert var.type.encapsulated is not None far_inner_type = var.type.encapsulated list_suffix = "" while far_inner_type.main == TypeEnum.LIST: assert far_inner_type.encapsulated is not None far_inner_type = far_inner_type.encapsulated list_suffix += "[]" lines = [ "{}{}{} = new {}[{}]{};".format( indent, (type_str(var.type) + " ") if decl else "", var.name, type_str(far_inner_type), size, list_suffix, ) ] index = self.iterator.new_it() self.words.push_scope() lines.append("{0}for (int {1} = 0; {1} < {2}; ++{1}) {{".format( indent, index, size)) lines.extend( self.read_lines( False, Variable(f"{var.name}[{index}]", "", var.type.encapsulated), var_name(var.type.encapsulated.size), indent_lvl + 1, )) self.words.pop_scope() self.iterator.pop_it() return lines + [indent + "}"] def call(self, reprint: bool) -> List[str]: """Declare and call the function take all inputs in arguments""" lines = [INDENTATION + "/**"] arguments = [] for arg in self.input.input: arg_name = var_name(arg.name) lines.append(INDENTATION + " * @param {} {}".format(arg_name, arg.comment)) arguments.append("{} {}".format(type_str(arg.type), arg_name)) lines.append(INDENTATION + " */") lines.append("{}static void {}({}) {{".format( INDENTATION, var_name(self.input.name), ", ".join(arguments))) if reprint: for variables in self.input.get_all_vars(): if len(variables) == 1: var = variables[0] lines.extend( self.print_lines( Variable(var_name(var.name), "", var.type, var.format_style), var_name(var.type.size), 2, )) else: lines.append(INDENTATION * 2 + 'System.out.printf("{}\\n", {});'.format( " ".join(["%d"] * len(variables)), ", ".join( var_name(i.name) for i in variables), )) else: lines.extend([ 2 * INDENTATION + i for i in textwrap.wrap( "/* TODO " + self.input.output + " */", 79 - 2 * len(INDENTATION), ) ]) return lines + [INDENTATION + "}"] def print_line(self, name: str, type_: Type) -> str: """Print the content of a var that holds in one line""" assert type_.fits_in_one_line(self.input.structs) if type_.main in (TypeEnum.INT, TypeEnum.CHAR, TypeEnum.STR): return f"System.out.println({name});" if type_.main == TypeEnum.LIST: assert type_.encapsulated is not None if type_.encapsulated.main == TypeEnum.CHAR: return f"System.out.println(new String({name}));" assert type_.encapsulated.main == TypeEnum.INT self.imports.add("java.util.Arrays") self.imports.add("java.util.stream.Collectors") return "System.out.println(Arrays.stream({}).mapToObj({}".format( name, 'String::valueOf).collect(Collectors.joining(" ")));') assert type_.main == TypeEnum.STRUCT fields = self.input.get_struct(type_.struct_name).fields return 'System.out.printf("{}\\n", {});'.format( " ".join("%d" if f.type.main == TypeEnum.INT else "%c" for f in fields), ", ".join("{}.{}".format(name, var_name(f.name)) for f in fields), ) def print_lines( self, var: Variable, size: str, indent_lvl: int, ) -> List[str]: """Print the content of a var that holds in one or more lines""" if var.fits_in_one_line(self.input.structs): return [ INDENTATION * indent_lvl + self.print_line(var.name, var.type) ] if var.type.main == TypeEnum.STRUCT: struct = self.input.get_struct(var.type.struct_name) lines = [] for f_name, f_type, f_size in struct.fields_name_type_size( f"{var.name}.{{}}", var_name): lines.extend( self.print_lines(Variable(f_name, "", f_type), f_size, indent_lvl)) return lines assert var.type.main == TypeEnum.LIST assert var.type.encapsulated is not None index = self.iterator.new_it() self.words.push_scope() lines = [ "{0}for (int {1} = 0; {1} < {2}; ++{1}) {{".format( INDENTATION * indent_lvl, index, size) ] lines.extend( self.print_lines( Variable(f"{var.name}[{index}]", "", var.type.encapsulated), var_name(var.type.encapsulated.size), indent_lvl + 1, )) lines.append(INDENTATION * indent_lvl + "}") self.words.pop_scope() self.iterator.pop_it() return lines def content(self, reprint: bool) -> str: """Return the parser content""" output = "" for struct in self.input.structs: output += f"/**\n * {struct.comment}\n */\n" output += "class {}\n{{\n".format(class_name(struct.name)) for field in struct.fields: decl_field = "{0}/**\n{0} * {1}\n{0} */\n{0}public {2} {3};\n" output += decl_field.format( INDENTATION, field.comment, type_str(field.type), var_name(field.name), ) output += "}\n\n" output += "class Main {\n" output += "\n".join(self.call(reprint)) + "\n\n" output += ( INDENTATION + "public static void main(String[] args) throws java.io.IOException {\n" ) output += 2 * INDENTATION + ( "BufferedReader reader = " "new BufferedReader(new InputStreamReader(System.in));\n") for variables in self.input.get_all_vars(): if len(variables) == 1: var = variables[0] for line in self.read_lines( True, Variable(var_name(var.name), "", var.type, var.format_style), var_name(var.type.size), 2, ): output += line + "\n" else: words = self.words.next_name() output += (f"{INDENTATION * 2}String[] {words}" ' = reader.readLine().split(" ");\n') for i, var in enumerate(variables): assert var.type.main == TypeEnum.INT output += ( INDENTATION * 2 + f"int {var_name(var.name)} = Integer.parseInt({words}[{i}]);\n" ) args = (var_name(var.name) for var in self.input.input) output += "\n{}{}({});\n".format(INDENTATION * 2, var_name(self.input.name), ", ".join(args)) output += INDENTATION + "}\n}\n" return "".join(f"import {i};\n" for i in sorted(self.imports)) + "\n" + output
class ParserPascal: """Create the Pascal code to parse an input""" def __init__(self, input_data: Input) -> None: self.input = input_data self.includes = set() # type: Set[str] self.main = [] # type: List[str] self.iterator = IteratorName([var.name for var in input_data.input]) self.local_integers = set() # type: Set[str] self.local_char = False self.indent_lvl = 0 def read_line(self, name: str, type_: Type, size: str) -> None: """Read an entire line and store it into the right place(s)""" assert type_.fits_in_one_line(self.input.structs) indent = INDENTATION * self.indent_lvl if type_.main == TypeEnum.INT: self.main.append(indent + "readln({});".format(name)) elif type_.main == TypeEnum.CHAR: self.main.append(indent + "readln({});".format(name)) elif type_.main == TypeEnum.STR: self.main.append(indent + "readln({});".format(name)) elif type_.main == TypeEnum.LIST: assert type_.encapsulated is not None if type_.encapsulated.main == TypeEnum.CHAR: self.main.append(indent + "readln({});".format(name)) else: assert type_.encapsulated.main == TypeEnum.INT index = self.iterator.new_it() self.local_integers.add(index) self.main.append( indent + "for {} := 0 to {} - 1 do".format(index, size) ) self.main.append( INDENTATION + indent + "read({}[{}]);".format(name, index) ) self.main.append(indent + "readln();") self.iterator.pop_it() else: assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) args = [] for i, field in enumerate(struct.fields): if i != 0 and field.type.main == TypeEnum.CHAR: args.append("_") self.local_char = True args.append(name + "." + var_name(field.name)) self.main.append(indent + "readln({});".format(", ".join(args))) def read_lines( self, name: str, type_: Type, size: str, style: FormatStyle = FormatStyle.DEFAULT, ) -> None: """Read one or several lines and store them into the right place(s)""" if type_.fits_in_one_line(self.input.structs, style): self.read_line(name, type_, size) else: if type_.main == TypeEnum.STRUCT: struct = self.input.get_struct(type_.struct_name) for f_name, f_type, f_size in struct.fields_name_type_size( "{}.{{}}".format(name), var_name ): self.main.extend( [ INDENTATION * self.indent_lvl + i for i in init_list(f_name, f_type, f_size) ] ) self.read_lines(f_name, f_type, f_size) else: assert type_.main == TypeEnum.LIST assert type_.encapsulated is not None index = self.iterator.new_it() self.local_integers.add(index) self.main.append( f"{INDENTATION * self.indent_lvl}for {index} := 0 to {size} - 1 do" ) self.main.append(INDENTATION * self.indent_lvl + "begin") self.indent_lvl += 1 self.read_lines( f"{name}[{index}]", type_.encapsulated, var_name(type_.encapsulated.size), ) self.indent_lvl -= 1 self.main.append(INDENTATION * self.indent_lvl + "end;") self.iterator.pop_it() def call(self, reprint: bool) -> List[str]: """Declare and call the function take all inputs in arguments""" name = var_name(self.input.name) arguments = [] method = [] for arg in self.input.input: arg_name = var_name(arg.name) method.append("{{ @param {} {} }}".format(arg_name, arg.comment)) const = "" if arg.type.main in (TypeEnum.INT, TypeEnum.CHAR) else "const " arguments.append("{}{}: {}".format(const, arg_name, type_str(arg))) method.append("procedure {}({});".format(name, "; ".join(arguments))) if reprint and self.local_integers: method.append("var") method.append( INDENTATION + "{}: longint;".format(", ".join(sorted(self.local_integers))) ) method.append("begin") if reprint: self.indent_lvl += 1 for var in self.input.input: method.extend( self.print_lines( var_name(var.name), var.type, var_name(var.type.size), var.format_style, ) ) self.indent_lvl -= 1 else: method.extend( textwrap.wrap( self.input.output + " *}", 79, initial_indent=INDENTATION + "{* " + "TODO ", subsequent_indent=INDENTATION, ) ) method.append("end;") return method def print_line( self, name: str, type_: Type, size: str, style: FormatStyle ) -> List[str]: """Print the content of a var that holds in one line""" assert type_.fits_in_one_line(self.input.structs, style) indent = INDENTATION * self.indent_lvl if type_.main in (TypeEnum.INT, TypeEnum.CHAR, TypeEnum.STR): return [ indent + ( f"write({name}, ' ');" if style == FormatStyle.NO_ENDLINE else f"writeln({name});" ) ] if type_.main == TypeEnum.LIST: assert type_.encapsulated is not None if type_.encapsulated.main == TypeEnum.CHAR: return [indent + f"writeln({name});"] lines = [] index = self.iterator.new_it() lines.append(indent + f"for {index} := 0 to {size} - 2 do") lines.append(indent + INDENTATION + f"write({name}[{index}], ' ');") try: size_int = int(size) if size_int > 0: lines.append(indent + f"write({name}[{size_int - 1}]);") except ValueError: lines.append( indent + f"if ({size} > 0) then write({name}[{size} - 1]);" ) lines.append(indent + "writeln();") self.iterator.pop_it() return lines assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) args = ["' '"] * (2 * len(struct.fields) - 1) args[::2] = [name + "." + var_name(i.name) for i in struct.fields] return [indent + f"writeln({', '.join(args)});"] def print_lines( self, name: str, type_: Type, size: str, style: FormatStyle = FormatStyle.DEFAULT, ) -> List[str]: """Print the content of a var that holds in one or more lines""" if type_.fits_in_one_line(self.input.structs, style): return self.print_line(name, type_, size, style) lines = [] if type_.main == TypeEnum.STRUCT: struct = self.input.get_struct(type_.struct_name) struct = self.input.get_struct(type_.struct_name) for f_name, f_type, f_size in struct.fields_name_type_size( f"{name}.{{}}", var_name ): lines.extend(self.print_lines(f_name, f_type, f_size)) else: assert type_.main == TypeEnum.LIST assert type_.encapsulated is not None index = self.iterator.new_it() lines = [ f"{INDENTATION * self.indent_lvl}for {index} := 0 to {size} - 1 do", INDENTATION * self.indent_lvl + "begin", ] self.indent_lvl += 1 lines.extend( self.print_lines( f"{name}[{index}]", type_.encapsulated, var_name(type_.encapsulated.size), ) ) self.indent_lvl -= 1 lines.append(INDENTATION * self.indent_lvl + "end;") self.iterator.pop_it() return lines def content(self, reprint: bool) -> str: """Return the parser content""" for variables in self.input.get_all_vars(): if len(variables) == 1: var = variables[0] self.main.extend(init_list(var_name(var.name), var.type)) self.read_lines( var_name(var.name), var.type, var_name(var.type.size), var.format_style, ) else: assert all(var.type.main == TypeEnum.INT for var in variables) self.main.append( f"readln({', '.join(var_name(i.name) for i in variables)});" ) method = self.call(reprint) output = "program {};\n\n".format(var_name(self.input.name)) types = decl_types(self.input.input) if self.input.structs or types: output += "type\n" for struct in self.input.structs: output += INDENTATION + "{{ {} }}\n".format(struct.comment) output += INDENTATION + "{} = record\n".format(var_name(struct.name)) for field in struct.fields: output += 2 * INDENTATION + "{}: {}; {{ {} }}\n".format( var_name(field.name), type_str(field, True), field.comment ) output += INDENTATION + "end;\n\n" if types: output += "\n".join(types) + "\n\n" for line in method: output += line + "\n" output += "\nvar\n" for var in self.input.input: output += INDENTATION + "{}: {}; {{ {} }}\n".format( var_name(var.name), type_str(var), var.comment ) if self.local_integers: output += INDENTATION + "{}: longint;\n".format( ", ".join(sorted(self.local_integers)) ) if self.local_char: output += INDENTATION + "_: char;\n" output += "begin\n" for line in self.main: output += INDENTATION + line + "\n" output += INDENTATION + "{}({});\n".format( var_name(self.input.name), ", ".join([var_name(i.name) for i in self.input.input]), ) output += "end.\n" return output
class ParserD: """Create the D code to parse an input""" def __init__(self, input_data: Input) -> None: self.input = input_data self.imports = {"std.stdio": {"stdin"}} self.iterator = IteratorName([var.name for var in input_data.input]) def add_import(self, module: str, symbol: str) -> None: """Add a new import statement""" if module in self.imports: self.imports[module].add(symbol) else: self.imports[module] = {symbol} def read_line(self, name: str, type_: Type) -> str: """Read a variable in one line of stdin""" assert type_.fits_in_one_line(self.input.structs) if type_.main == TypeEnum.INT: return 'stdin.readf("%d\\n", &{});'.format(name) if type_.main == TypeEnum.STR: return 'stdin.readf("%s\\n", &{});'.format(name) if type_.main == TypeEnum.CHAR: return 'stdin.readf("%c\\n", &{});'.format(name) if type_.main == TypeEnum.LIST: assert type_.encapsulated self.add_import("std.array", "split") self.add_import("std.conv", "to") if type_.encapsulated.main == TypeEnum.INT: self.add_import("std.array", "array") self.add_import("std.algorithm.iteration", "map") return name + " = stdin.readln.split.map!(to!int).array;" assert type_.encapsulated.main == TypeEnum.CHAR self.add_import("std.string", "chop") return name + " = stdin.readln.chop.to!(char[]);" assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) return 'stdin.readf("{}\\n", {});'.format( " ".join("%c" if i.type.main == TypeEnum.CHAR else "%d" for i in struct.fields), ", ".join("&" + name + "." + var_name(i.name) for i in struct.fields), ) def read_lines( self, name: str, type_: Type, size: str, style: FormatStyle = FormatStyle.DEFAULT, ) -> List[str]: """Read a variable in one line or several lines of stdin""" if type_.fits_in_one_line(self.input.structs, style): return [self.read_line(name, type_)] if type_.main == TypeEnum.LIST: assert type_.encapsulated index = self.iterator.new_it() lines = [ "{}.length = {};".format(name, size), "for (size_t {0} = 0; {0} < {1}.length; {0}++)".format( index, name), "{", ] lines.extend([ INDENTATION + i for i in self.read_lines( "{}[{}]".format(name, index), type_.encapsulated, var_name(type_.encapsulated.size), ) ]) self.iterator.pop_it() return lines + ["}"] assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) lines = [] for f_name, f_type, f_size in struct.fields_name_type_size( "{}.{{}}".format(name), var_name): lines.extend(self.read_lines(f_name, f_type, f_size)) return lines def read_var(self, var: Variable) -> List[str]: """Read a variable from stdin""" return ["{} {};".format(type_str(var.type), var_name(var.name)) ] + self.read_lines(var_name(var.name), var.type, var_name(var.type.size), var.format_style) def print_lines(self, name: str, type_: Type, style: FormatStyle = FormatStyle.DEFAULT) -> List[str]: """Print a D variable""" if type_.main in (TypeEnum.INT, TypeEnum.STR, TypeEnum.CHAR): self.add_import("std.stdio", "writeln") return ["writeln({});".format(name)] if type_.main == TypeEnum.LIST: assert type_.encapsulated if (type_.encapsulated.main == TypeEnum.INT and style != FormatStyle.FORCE_NEWLINES): self.add_import("std.array", "join") self.add_import("std.algorithm.iteration", "map") self.add_import("std.conv", "to") return ['writeln(join({}.map!(to!string), " "));'.format(name)] if type_.encapsulated.main == TypeEnum.CHAR: return ["writeln({});".format(name)] index = self.iterator.new_it() lines = [ "for (size_t {0} = 0; {0} < {1}.length; {0}++)".format( index, name), "{", ] lines.extend([ INDENTATION + i for i in self.print_lines( "{}[{}]".format(name, index), type_.encapsulated) ]) self.iterator.pop_it() return lines + ["}"] assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) if type_.fits_in_one_line(self.input.structs, style): self.add_import("std.stdio", "writefln") return [ 'writefln("{}", {});'.format( " ".join("%c" if i.type.main == TypeEnum.CHAR else "%d" for i in struct.fields), ", ".join(name + "." + var_name(i.name) for i in struct.fields), ) ] lines = [] for field in struct.fields: lines.extend( self.print_lines("{}.{}".format(name, var_name(field.name)), field.type)) return lines def function(self, reprint: bool) -> List[str]: """Return the code of the function to complete by the end user""" lines = ["/**", "Params:"] lines.extend( "{}{} = {}".format(INDENTATION, var_name(i.name), i.comment) for i in self.input.input) lines.append("*/") lines.extend([ "void {}({})".format( var_name(self.input.name), ", ".join( type_str(i.type) + " " + var_name(i.name) for i in self.input.input), ), "{", ]) if reprint: for variables in self.input.get_all_vars(): if len(variables) == 1: var = variables[0] lines.extend(INDENTATION + i for i in self.print_lines( var_name(var.name), var.type, var.format_style)) else: self.add_import("std.stdio", "writeln") lines.append(INDENTATION + "writeln(" + ', " ", '.join( var_name(i.name) for i in variables) + ");") else: lines.extend( textwrap.wrap( self.input.output, 79, initial_indent=INDENTATION + "// TODO ", subsequent_indent=INDENTATION + "// ", )) return lines + ["}"] def content(self, reprint: bool) -> str: """Return content of the D file for parsing the input""" output = "" for struct in self.input.structs: output += "/// {}\n".format(struct.comment) output += "struct {}\n{{\n".format(struct_name(struct.name)) for field in struct.fields: output += INDENTATION + "{} {}; /// {}\n".format( type_str(field.type), var_name(field.name), field.comment) output += "}\n\n" output += "\n".join(self.function(reprint)) + "\n\n" output += "void main()\n{\n" for variables in self.input.get_all_vars(): if len(variables) == 1: var = variables[0] for line in self.read_var(var): output += INDENTATION + line + "\n" else: assert all(var.type.main == TypeEnum.INT for var in variables) output += ( INDENTATION + f"int {', '.join(var_name(i.name) for i in variables)};\n") output += ( INDENTATION + f'stdin.readf("{" ".join(["%d"] * len(variables))}\\n", ' + f"{', '.join('&' + var_name(i.name) for i in variables)});\n" ) args = (var_name(i.name) for i in self.input.input) output += "\n{}{}({});\n".format(INDENTATION, var_name(self.input.name), ", ".join(args)) output += "}\n" imports = "" for module in sorted(self.imports.keys()): imports += "import {} : {};\n".format( module, ", ".join(sorted(self.imports[module]))) return f"module {var_name(self.input.name)};\n\n{imports}\n{output}"
class ParserPHP: """Create the PHP code to parse an input""" def __init__(self, input_data: Input): self.input = input_data self.iterator = IteratorName([var.name for var in input_data.input] + [input_data.name]) def read_lines(self, name: str, type_: Type, size: str, style: FormatStyle) -> List[str]: """Generate the PHP code to read the lines for a given type""" if type_.fits_in_one_line(self.input.structs, style): return [read_line(type_, self.input)] if type_.main == TypeEnum.LIST: assert type_.encapsulated is not None iterator = "$" + self.iterator.new_it() lines = [] if type_.encapsulated.fits_in_one_line(self.input.structs): # Here we don't really care if the encapsulated type really fits on # on line. What we are interested in, is that the fact that the code # generated to read it will fit on one line, and will need to be # directly assigned to a variable lines = [ f"{name}[{iterator}] = {read_line(type_.encapsulated, self.input)};" ] else: tmp_name = "$" + self.iterator.new_it() lines = self.read_lines( tmp_name, type_.encapsulated, var_name(type_.encapsulated.size), FormatStyle.DEFAULT, ) lines.append(f"{name}[{iterator}] = {tmp_name};") self.iterator.pop_it() self.iterator.pop_it() prefix = [ f"{name} = new SplFixedArray({size});", f"for ({iterator} = 0; {iterator} < {size}; {iterator}++) {{", ] return prefix + [INDENTATION + i for i in lines] + ["}"] assert type_.main == TypeEnum.STRUCT struct = self.input.get_struct(type_.struct_name) lines = [] for f_name, f_type, f_size in struct.fields_name_type_size( '{}["{{}}"]'.format(name), lambda x: x): read = self.read_lines(f_name, f_type, f_size, FormatStyle.DEFAULT) if len(read) == 1: read[0] = "{} = {};".format(f_name, read[0]) lines.extend(read) return ["{} = [];".format(name)] + lines def read_vars(self) -> List[str]: """Generate the PHP code to read all input variables""" lines = [] for variables in self.input.get_all_vars(): name = ", ".join(var_name(i.name) for i in variables) type_ = variables[0].type style = variables[0].format_style if len(variables) != 1: name = f"list({name})" assert all(var.type.main == TypeEnum.INT for var in variables) type_ = Type(TypeEnum.LIST, str(len(variables)), Type(TypeEnum.INT)) style = FormatStyle.DEFAULT size = var_name(type_.size) read = self.read_lines(name, type_, size, style) if len(read) == 1: read[0] = f"{name} = {read[0]};" lines.extend(read) return lines
class ParserJS: """Create the Javascript code to parse an input""" def __init__(self, input_data: Input) -> None: self.input = input_data existing_names = [var_name(var.name) for var in input_data.input ] + [var_name(input_data.name)] self.iterator = IteratorName(existing_names) self.words = WordsName(existing_names) def read_line(self, decl: bool, name: str, type_: Type, size: str, indent_lvl: int) -> List[str]: # pylint: disable = too-many-arguments """Generate the Javascript code to read a line of given type""" assert type_.fits_in_one_line(self.input.structs) indent = INDENTATION * indent_lvl start = indent + ("const " if decl else "") + name + " = " if type_.main == TypeEnum.LIST: assert type_.encapsulated is not None if type_.encapsulated.main == TypeEnum.CHAR: return [start + 'stdin[line++].split("");'] assert type_.encapsulated.main == TypeEnum.INT return [ start + 'stdin[line++].split(" ", {}).map(Number);'.format(size) ] if type_.main == TypeEnum.STRUCT: struct = self.input.get_struct(type_.struct_name) words = self.words.next_name() lines = [ indent + 'const {} = stdin[line++].split(" ");'.format(words), start + "{", ] lines.extend(indent + INDENTATION + "{}: {}{}".format( var_name(field.name), "{}[{}]".format(words, i) if field.type.main == TypeEnum.CHAR else "Number({}[{}])".format(words, i), "," if i != len(struct.fields) - 1 else "", ) for i, field in enumerate(struct.fields)) return lines + [indent + "};"] return [ start + { TypeEnum.INT: "Number(stdin[line++]);", TypeEnum.CHAR: "stdin[line++];", TypeEnum.STR: "stdin[line++];", }[type_.main] ] def read_lines(self, decl: bool, var: Variable, size: str, indent_lvl: int) -> List[str]: # pylint: disable=too-many-arguments """Generate the Javascript code to read the lines for a given type""" if var.fits_in_one_line(self.input.structs): return self.read_line(decl, var.name, var.type, size, indent_lvl) indent = INDENTATION * indent_lvl if var.type.main == TypeEnum.LIST: assert var.type.encapsulated is not None lines = [indent + f"{'const ' if decl else ''}{var.name} = [];"] iterator = self.iterator.new_it() inner_name = self.iterator.new_it() lines.append(indent + "for (let {0} = 0; {0} < {1}; {0}++) {{".format( iterator, size)) self.words.push_scope() lines.extend( self.read_lines( True, Variable(inner_name, "", var.type.encapsulated), var_name(var.type.encapsulated.size), indent_lvl + 1, )) lines.append(indent + INDENTATION + f"{var.name}.push({inner_name});") self.words.pop_scope() self.iterator.pop_it() self.iterator.pop_it() return lines + [indent + "}"] assert var.type.main == TypeEnum.STRUCT struct = self.input.get_struct(var.type.struct_name) lines = [indent + f"{'const ' if decl else ''}{var.name} = {{}};"] for f_name, f_type, f_size in struct.fields_name_type_size( f"{var.name}.{{}}", var_name): lines.extend( self.read_lines(False, Variable(f_name, "", f_type), f_size, indent_lvl)) return lines def read_vars(self) -> List[str]: """Generate the Javascript code to read all input variables""" lines = [] for variables in self.input.get_all_vars(): if len(variables) == 1: var = variables[0] lines.extend( self.read_lines( True, Variable(var_name(var.name), "", var.type, var.format_style), var_name(var.type.size), 1, )) else: lines.append(INDENTATION + "const [" + ", ".join(var_name(i.name) for i in variables) + '] = stdin[line++].split(" ").map(Number);') return lines