public static BinaryFileSchema CheckBfs(BinaryFileSchema schema, IBfsErrorHandler errorHandler) { handler = errorHandler; IPhase[] phases = new IPhase[] { new Environments(), new TypeLinking(), new Hierarchy(), new TypeChecking(), new DefiniteAssignment() }; gotError = false; foreach (IPhase phase in phases) { phase.Check(schema); if (gotError && errorHandler != null) { errorHandler.HandleMessage("Schema has errors. Compilation stopped."); return null; } } return schema; }
public static BinaryFileSchema ParseBfs(BinaryFileSchema schema, string source, IBfsErrorHandler errorHandler) { gotError = false; handler = errorHandler; BinaryFileSchemaParser.BinaryFileSchemaParser parser = new BinaryFileSchemaParser.BinaryFileSchemaParser(); parser.Construct(source, new StreamErrorHandler(errorHandler) ); bool matches = false; try { matches = parser.bfschema(); } catch (PegException ex) { errorHandler.HandleMessage(ex.Message); } if (!matches) { ReportMessage("Schema didn't parse."); return null; } AstConvert converter = new AstConvert(schema,source); schema = converter.GetBFSTree(parser.GetRoot()); schema = CheckBfs(schema,errorHandler); return schema; }
public void Check(BinaryFileSchema schema) { foreach (IBfsDataBlock block in schema.DatablockList) { //Link all unresolved field-types to their declarations (data-blocks). if (block is IBfsStructType) { IBfsStructType structType = block as IBfsStructType; foreach (BfsStructField field in structType.StructFields.Values) if (field.FieldType is BfsUnresolvedNamedType) { BfsUnresolvedNamedType oldtype = (BfsUnresolvedNamedType)field.FieldType; if (schema.DataBlocks.ContainsKey(oldtype.Name)) { BfsNamedType newtype = new BfsNamedType(); newtype.DataBlock = schema.DataBlocks[oldtype.Name]; newtype.ArrayExtension = oldtype.ArrayExtension; newtype.SourceRange = oldtype.SourceRange; field.FieldType = newtype; } else BfsCompiler.ReportError(oldtype.SourceRange, "Could not resolve '" + oldtype.Name + "' to a type."); } } else if (block is BfsEnum) foreach (BfsEnumField field in (block as BfsEnum).EnumFields) CheckActionList(field.Actions, block); else if (block is BfsBitfield) foreach (BfsBitfieldField field in (block as BfsBitfield).BitFieldFields) CheckActionList(field.Actions, block); } }
private void IterateSchema( BinaryFileSchema schema ) { foreach (IBfsDataBlock block in schema.DatablockList) { TreeNode node = treeBFSstructure.Nodes.Add(block.Name); node.Tag = block; node.ImageIndex = node.SelectedImageIndex = 0; if (block is IBfsStructType) { if (block is IBfsConsumptionType) node.ImageIndex = node.SelectedImageIndex = 1; foreach (BfsStructField field in (block as IBfsStructType).StructFields.Values) { TreeNode newnode = node.Nodes.Add(field.ToString()); newnode.Tag = field; newnode.ImageIndex = newnode.SelectedImageIndex = 4; } } else if (block is BfsEnum) { node.ImageIndex = node.SelectedImageIndex = 2; foreach (BfsEnumField field in (block as BfsEnum).EnumFields) { TreeNode newnode = node.Nodes.Add(field.ToString()); newnode.Tag = field; newnode.ImageIndex = newnode.SelectedImageIndex = 4; } } else if (block is BfsBitfield) { node.ImageIndex = node.SelectedImageIndex = 3; foreach (BfsBitfieldField field in (block as BfsBitfield).BitFieldFields) { TreeNode newnode = node.Nodes.Add(field.ToString()); newnode.Tag = field; newnode.ImageIndex = newnode.SelectedImageIndex = 4; } } node.Expand(); } }
static void Main(string[] args) { //Command line code generator if (args.Length == 0) { Console.WriteLine("Error: No input schema..."); return; } ConsoleErrorHandler errorHandler = new ConsoleErrorHandler(); BinaryFileSchema schema = new BinaryFileSchema(args[0], errorHandler); if (schema == null || errorHandler.GotError) { Console.WriteLine("Could not generate C# code because of schema errors!"); return; } CSharpGenerator csgenerator = new CSharpGenerator(); string code = csgenerator.GenerateCode(schema); Console.WriteLine(code); }
public void Check(BinaryFileSchema schema) { bool formatfound = false; foreach (IBfsDataBlock block in schema.DatablockList) { bool elsefound = false; //Check that only one block is declared 'format'. if (block.IsFormat && formatfound == false) { formatfound = true; schema.FormatBlock = block; } else if (block.IsFormat && formatfound == true) BfsCompiler.ReportError(block.SourceRange, "Only one 'format' specifier is allowed per schema"); //Check that no two blocks have the same name and build map over types. if (schema.DataBlocks.ContainsKey(block.Name)) BfsCompiler.ReportError(block.SourceRange, "Duplicate datablock name not allowed: '" + block.Name + "'"); else schema.DataBlocks.Add(block.Name, block); //Build map over local variables foreach (BfsLocalField localfield in block.LocalFieldList) if (localfield.Name == "value") BfsCompiler.ReportError(localfield.SourceRange, "'value' is a reserved name for use in expressions in consumable types."); else if (block.LocalFields.ContainsKey(localfield.Name)) BfsCompiler.ReportError(localfield.SourceRange, "Duplicate local variable name not allowed: '" + localfield.Name + "'"); else block.LocalFields.Add(localfield.Name, localfield); //Check that no two struct fields in the same block have the same name. if (block is IBfsStructType) { IBfsStructType structblock = block as IBfsStructType; foreach (BfsStructField field in structblock.StructFieldList) { if (field.Name == "value") BfsCompiler.ReportError(field.SourceRange, "'value' is a reserved name for use in expressions in consumable types."); else if (structblock.StructFields.ContainsKey(field.Name)) BfsCompiler.ReportError(field.SourceRange, "Duplicate field name not allowed: '" + field.Name + "'"); else structblock.StructFields.Add(field.Name, field); } //Check that no local variables have the same name foreach (BfsStructField field in structblock.StructFieldList) if (structblock.LocalFields.ContainsKey(field.Name)) BfsCompiler.ReportError(field.SourceRange, "Name clash with local variable: '" + field.Name + "'"); //Check that only supported compressions methods are defined if (structblock.CompressionMethod != null) if(structblock.CompressionMethod != "GZip" && structblock.CompressionMethod != "Deflate") BfsCompiler.ReportError(structblock.CompressionRange, "Unknown compression method: '" + structblock.CompressionMethod + "'. Expected 'GZip' or 'Deflate'."); } if (block is BfsEnum) { BfsEnum enumblock = block as BfsEnum; enumblock.SizeInBytes = GetSizeOfPrimitiveType(enumblock.PrimitiveType); HashSet<long> enumvalues = new HashSet<long>(); HashSet<BfsEnumRange> enumranges = new HashSet<BfsEnumRange>(); foreach (BfsEnumField field in enumblock.EnumFields) { //Check that there is only one 'else'. bool isElse = (field.EnumMatch is BfsEnumElse); if (isElse && elsefound == false) elsefound = true; else if (isElse && elsefound == true) BfsCompiler.ReportError(field.SourceRange, "Only one 'else' event allowed"); //Building map from name to enum field aliases if (field.Alias != null && !enumblock.EnumAliases.ContainsKey(field.Alias)) { BfsEnumFieldAlias alias = new BfsEnumFieldAlias(); alias.Name = field.Alias; enumblock.EnumAliases.Add(field.Alias, alias); } //Check that no numbers or ranges intersect. if (field.EnumMatch is BfsEnumValue) { BfsEnumValue e_val = (field.EnumMatch as BfsEnumValue); foreach (int val in enumvalues) if (e_val.Value == val) BfsCompiler.ReportError(field.SourceRange, "Value already defined: '" + val + "'"); foreach (BfsEnumRange range in enumranges) CheckValueOnRange(e_val.Value, range, field); enumvalues.Add(e_val.Value); } if (field.EnumMatch is BfsEnumRange) { BfsEnumRange range = field.EnumMatch as BfsEnumRange; if (range.EndValue <= range.StartValue) BfsCompiler.ReportError(range.SourceRange, "End-value must be larger than start-value in the range"); long actualRange = range.EndValue - range.StartValue + 1; if (range.StartInclusion == BfsInclusionEnum.Excluded) actualRange--; if (range.EndInclusion == BfsInclusionEnum.Excluded) actualRange--; if (actualRange == 0) BfsCompiler.ReportError(range.SourceRange, "Range is empty because of the inclusions brackets: '" + range + "'"); if (actualRange == 1) BfsCompiler.ReportWarning(range.SourceRange, "Range is of length 1, why not use a single value instead?: '" + range + "'"); foreach (int val in enumvalues) CheckValueOnRange(val, range, field); foreach (BfsEnumRange rb in enumranges) CheckRangeOnRange(range, rb, field); enumranges.Add(range); } } } HashSet<long> bits = new HashSet<long>(); HashSet<string> bitnames = new HashSet<string>(); if (block is BfsBitfield) { BfsBitfield bitfield = block as BfsBitfield; bitfield.SizeInBytes = GetSizeOfPrimitiveType(bitfield.PrimitiveType); foreach (BfsBitfieldField field in bitfield.BitFieldFields) { //Check that no bit-indexes are listed twice. if (bits.Contains(field.BitNumber)) BfsCompiler.ReportError(field.SourceRange, "Bit may only be listed once: '" + field.BitNumber + "'"); else bits.Add(field.BitNumber); //Check that no bit-names are listed twice. if (field.Name != null && bitnames.Contains(field.Name)) BfsCompiler.ReportError(field.SourceRange, "Two identical bitnames found: '" + field.Name + "'"); else if(field.Name != null) bitnames.Add(field.Name); //Check that the bit-indexes doesn't exeed the size of the primitive type. long sizeoftype = GetSizeOfPrimitiveType(bitfield.PrimitiveType) * 8 - 1; if (field.BitNumber > sizeoftype) BfsCompiler.ReportError(field.SourceRange, "Bit-index exceeds the boundary of the primitive type: '" + field.BitNumber + "' > " + sizeoftype); } } } if (schema.FormatBlock == null) BfsCompiler.ReportError("No 'format' block specified. Schema needs an entry point."); }
public static void ColorizeSchema(BinaryFileSchema schema, RichTextBox richTextBox) { textBox = richTextBox; richTextBox.SelectAll(); richTextBox.SelectionColor = Color.Black; richTextBox.SelectionFont = normalfont; //Colorize the byte-order if ( schema.ByteOrder != null && schema.ByteOrder.ByteOrder != BfsByteOrderEnum.LanguageDefault) { richTextBox.Select(schema.ByteOrder.SourceRange.Begin, schema.ByteOrder.SourceRange.Length); richTextBox.SelectionColor = keywordcolor; } foreach (IBfsDataBlock block in schema.DatablockList) { ColorRange(block.SourceRange, normalcolor, boldfont); ColorRange(block.BlockTypeSourceRange, keywordcolor, boldfont); if (block.IsFormat) ColorRange(block.FormatSourceRange, keywordcolor, boldfont); if (block is IBfsConsumptionType) { IBfsConsumptionType special = block as IBfsConsumptionType; ColorRange(special.PrimitiveType.SourceRange, typecolor); } foreach (BfsLocalField lfield in block.LocalFields.Values) { ColorRange(lfield.SourceRange, 5, keywordcolor); ColorRange(lfield.PrimitiveType.SourceRange, typecolor); if (lfield.AssignmentExpression != null) ColorExpression(lfield.AssignmentExpression.ExpressionGroup); } if (block is IBfsStructType) { IBfsStructType structtype = block as IBfsStructType; if (structtype.CompressionMethod != null) ColorRange(structtype.CompressionRange, compressioncolor); foreach (BfsStructField field in structtype.StructFields.Values) { ColorRange(field.FieldType.SourceRange, typecolor); if (field.FieldType is BfsFunctionType) ColorRange((field.FieldType as BfsFunctionType).ArgumentSourceRange, stringcolor); if (field.Conditional != null) { ColorRange(field.ConditionalSourceRange, 2, keywordcolor); ColorExpression(field.Conditional.ExpressionGroup); } if (field.Skip) ColorRange(field.SkipSourceRange, skipcolor); if (field.FieldType.ArrayExtension != null && field.FieldType.ArrayExtension is BfsKnownArray) ColorExpression((field.FieldType.ArrayExtension as BfsKnownArray).Expression.ExpressionGroup); else if (field.FieldType.ArrayExtension != null && field.FieldType.ArrayExtension is BfsUnknownArray) { BfsUnknownArray array = field.FieldType.ArrayExtension as BfsUnknownArray; ColorRange(array.UntilSourceRange, keywordcolor); foreach (BfsSourceRange range in array.OrWords) ColorRange(range, keywordcolor); foreach (IBfsStopCase stopcase in array.StopCases) { if (stopcase is BfsStopCaseString) ColorRange(stopcase.SourceRange, stringcolor); else if (stopcase is BfsStopCaseEndOfFile) ColorRange(stopcase.SourceRange, enumaliascolor); else if (stopcase is BfsStopCaseHex) ColorRange(stopcase.SourceRange, numbercolor); BfsSourceRange zerorange = new BfsSourceRange(); if (stopcase.InclusionSourceRange != zerorange) ColorRange(stopcase.InclusionSourceRange, keywordcolor); } } } } else if (block is BfsEnum) foreach (BfsEnumField field in (block as BfsEnum).EnumFields) { if (field.Alias != null) ColorRange(field.AliasSourceRange, enumaliascolor); if (field.EnumMatch is BfsEnumValue) ColorRange(field.EnumMatch.SourceRange, numbercolor); else if (field.EnumMatch is BfsEnumRange) ColorRange(field.EnumMatch.SourceRange.Begin + 1, field.EnumMatch.SourceRange.Length - 2, numbercolor); else if (field.EnumMatch is BfsEnumElse) ColorRange(field.EnumMatch.SourceRange, keywordcolor); ColorActionList(field.Actions); } else if (block is BfsBitfield) { foreach (BfsBitfieldField field in (block as BfsBitfield).BitFieldFields) { ColorRange(field.SourceRange, numbercolor); ColorActionList(field.Actions); } } } }
public void Check( BinaryFileSchema schema ) { foreach (IBfsDataBlock block in schema.DatablockList) { if (!(block is IBfsStructType)) continue; //Clear before each run as nodes will otherwise be seen as visited in the next data block. topoDictionary.Clear(); IBfsStructType structType = block as IBfsStructType; BfsTopologicalSorting topological = new BfsTopologicalSorting(); BfsTopologicalNode prevField = null; foreach ( BfsStructField field in structType.StructFieldList) { BfsTopologicalNode node = GetTopoNode(field); topological.Nodes.Add(node); //Make each struct field dependent on the previous field. if (prevField != null) node.Nodes.Add(prevField); else prevField = node; if (field.Conditional != null) foreach (BfsExpressionVariable expVar in field.Conditional.DependantVariables) node.Nodes.Add(GetTopoNode(expVar.LastField)); if (field.PrimitiveType.ArrayExtension != null && field.PrimitiveType.ArrayExtension is BfsKnownArray) { BfsKnownArray knownArray = field.PrimitiveType.ArrayExtension as BfsKnownArray; foreach (BfsExpressionVariable expVar in knownArray.Expression.DependantVariables) node.Nodes.Add(GetTopoNode(expVar.LastField)); } } //Add all the structure field as well as their dependancies foreach (BfsLocalField local in structType.LocalFieldList) { BfsTopologicalNode node = GetTopoNode(local); if(local.AssignmentExpression != null) foreach (BfsExpressionVariable expVar in local.AssignmentExpression.DependantVariables) node.Nodes.Add(GetTopoNode(expVar.LastField)); topological.Nodes.Add(node); } //Find the execution/parse order of the struct fields and local fields by performing a topological sort. structType.ParseOrder = topological.TopologicalSort(); } foreach (IBfsDataBlock block in schema.DatablockList) { //Check that local-fields aren't used in their own intialization expression. foreach (BfsLocalField local in block.LocalFieldList) if (local.AssignmentExpression != null) foreach (BfsExpressionVariable expvar in local.AssignmentExpression.DependantVariables) if (expvar.NameHierarchy[0] == local) BfsCompiler.ReportError(local.SourceRange, "Cannot use local variable in it's own initilization expression"); if (block is IBfsStructType) { bool foundEOFcase = false; BfsStructField eofCase = null; IBfsStructType structType = (IBfsStructType)block; HashSet<string> namesSeenSoFar = new HashSet<string>(structType.LocalFields.Keys); foreach (BfsStructField field in structType.StructFields.Values) { if (foundEOFcase) BfsCompiler.ReportError(field.SourceRange, "Array '"+eofCase.Name+"' cannot have an EOF case because there are remaining fields in the struct."); //Check that no variables in conditional expressions or array length expressions aren't read from the file yet. //Check that struct-fields aren't used in their conditional expression. if (field.Conditional != null) foreach (BfsExpressionVariable var in field.Conditional.DependantVariables) if (!namesSeenSoFar.Contains(var.NameHierarchy[0].Name) && !(var.NameHierarchy[0] is BfsEnumAliasExp)) BfsCompiler.ReportError(var.SourceRange, " The variable '" + var.ToString() + "' cannot be used before it is read from the file."); if (field.FieldType.ArrayExtension != null && field.FieldType.ArrayExtension is BfsKnownArray) { BfsKnownArray knownArray = field.FieldType.ArrayExtension as BfsKnownArray; foreach (BfsExpressionVariable var in knownArray.Expression.DependantVariables) if (!namesSeenSoFar.Contains(var.NameHierarchy[0].Name) && !(var.NameHierarchy[0] is BfsEnumAliasExp)) BfsCompiler.ReportError(var.SourceRange, " The variable '" + var.ToString() + "' cannot be used before it is read from the file."); } namesSeenSoFar.Add(field.Name); //Check that no struct fields come after an unknown array extension only terminating at EOF //Check that no stopcases comes after an EOF if (field.FieldType.ArrayExtension is BfsUnknownArray) { BfsUnknownArray extension = field.FieldType.ArrayExtension as BfsUnknownArray; bool stopcaseafter = false; foreach (IBfsStopCase stopcase in extension.StopCases) { if (stopcaseafter) BfsCompiler.ReportWarning(stopcase.SourceRange, "Stopcase after an EOF will never be triggered. Move the EOF to the end of the list."); if (stopcase is BfsStopCaseEndOfFile) { stopcaseafter = true; foundEOFcase = true; eofCase = field; } } } } } } }
public AstConvert(string source) { this.schema = new BinaryFileSchema(); this.source = source; }
public AstConvert(BinaryFileSchema schema, string source) { this.schema = schema; this.source = source; }
public void Check( BinaryFileSchema schema ) { foreach (IBfsDataBlock block in schema.DatablockList) { //Assignment expressions on local variables foreach (BfsLocalField local in block.LocalFieldList) if (local.AssignmentExpression != null) { if (local.PrimitiveType.ArrayExtension != null) BfsCompiler.ReportError(local.SourceRange, "Local variables with array extensions cannot have assignment expressions."); CheckExpression(local.AssignmentExpression, block); CheckAssignment(local.SourceRange, local.PrimitiveType.PrimitiveType, local.AssignmentExpression.PrimitiveType); } //Check conditional expressions + array extensions if (block is IBfsStructType) { IBfsStructType structType = (IBfsStructType)block; foreach (BfsStructField field in structType.StructFields.Values) { if (field.Conditional != null) { CheckExpression(field.Conditional, block); if (field.Conditional.PrimitiveType != BfsPrimitiveTypeEnum.Bool) BfsCompiler.ReportError(field.Conditional.SourceRange, "The conditional isn't of boolean type!"); } if (field.FieldType.ArrayExtension != null && field.FieldType.ArrayExtension is BfsKnownArray) { BfsKnownArray arr = field.FieldType.ArrayExtension as BfsKnownArray; CheckExpression(arr.Expression, block); if (arr.Expression.PrimitiveType <= BfsPrimitiveTypeEnum.Bool && arr.Expression.PrimitiveType != BfsPrimitiveTypeEnum.CallExpression) BfsCompiler.ReportError(arr.SourceRange, "Unsuitable type for array-extension: " + arr.Expression.PrimitiveType ); } } } // All the expressions in action-lists for both Enums and BitFields else if (block is BfsEnum) { foreach (BfsEnumField field in (block as BfsEnum).EnumFields) if (field.Actions != null) foreach (IBfsAction action in field.Actions) if (action is BfsActionAssignment) { BfsActionAssignment a = action as BfsActionAssignment; CheckExpression(a.Expression, block); CheckAssignment(a.SourceRange, a.LocalVariable.PrimitiveType.PrimitiveType, a.Expression.PrimitiveType); } } else if (block is BfsBitfield) { foreach (BfsBitfieldField field in (block as BfsBitfield).BitFieldFields) if (field.Actions != null) foreach (IBfsAction action in field.Actions) if (action is BfsActionAssignment) { BfsActionAssignment a = action as BfsActionAssignment; CheckExpression(a.Expression, block); CheckAssignment(a.SourceRange, a.LocalVariable.PrimitiveType.PrimitiveType, a.Expression.PrimitiveType); } } } }
public void OpenSchema(string filename) { BfsErrorHandler errorHandler = new BfsErrorHandler(listView1); toolStripStatusLabel1.Text = "Opening schema: " + filename; schema = new BinaryFileSchema(filename, errorHandler); }
private void ParseGrammar( ) { richTextBox.AllowPaint = false; treeBFSstructure.BeginUpdate(); listViewErrorBox.BeginUpdate(); IBfsErrorHandler errorHandler = new ListViewErrorHandler(listViewErrorBox); string source = richTextBox.Text; listViewErrorBox.Items.Clear(); treeBFSstructure.Nodes.Clear(); Stopwatch timer = new Stopwatch(); timer.Start(); BinaryFileSchema schema = BfsCompiler.ParseBfs(source, errorHandler); timer.Stop(); if (schema != null) { errorHandler.HandleMessage("Parsed and processed in " + timer.ElapsedMilliseconds + " milliseconds (" + timer.ElapsedTicks + " ticks)"); IterateSchema(schema); SchemaColorizer.ColorizeSchema(schema, richTextBox); toolGenerateCode.Enabled = true; lastSchema = schema; } else toolGenerateCode.Enabled = false; richTextBox.AllowPaint = true; treeBFSstructure.EndUpdate(); listViewErrorBox.EndUpdate(); }