diff options
Diffstat (limited to 'cmake/elfinfo/src')
10 files changed, 421 insertions, 29 deletions
diff --git a/cmake/elfinfo/src/main/antlr4/Test1Lexer.g4 b/cmake/elfinfo/src/main/antlr4/Test1Lexer.g4 new file mode 100644 index 0000000..142229d --- /dev/null +++ b/cmake/elfinfo/src/main/antlr4/Test1Lexer.g4 @@ -0,0 +1,22 @@ +lexer grammar Test1Lexer; + +channels { + WHITESPACE_CHANNEL +} + +NAME : [a-z]+; + +// Characters +C_PLUS : '+'; +C_MINUS : '-'; +C_QUOTE : '"' -> skip, pushMode(STRING); + +//SPACE : [ ]; + +WS + : [ \t\r\n]+ -> channel(WHITESPACE_CHANNEL) + ; + +mode STRING; +STRING_ANY : ~'"'; +STRING_END_QUOTE : '"' -> skip, popMode; diff --git a/cmake/elfinfo/src/main/antlr4/Test1Parser.g4 b/cmake/elfinfo/src/main/antlr4/Test1Parser.g4 new file mode 100644 index 0000000..affdfe5 --- /dev/null +++ b/cmake/elfinfo/src/main/antlr4/Test1Parser.g4 @@ -0,0 +1,23 @@ +parser grammar Test1Parser; + +options { + tokenVocab = Test1Lexer; +} + +name + : NAME + | STRING_ANY* + ; + +file + : stmt* + ; + +stmt + : expr + ; + +expr + : name C_PLUS name + | name C_MINUS name + ; diff --git a/cmake/elfinfo/src/main/java/io/trygvis/ld/CollectingErrorListener.java b/cmake/elfinfo/src/main/java/io/trygvis/ld/CollectingErrorListener.java new file mode 100644 index 0000000..968a02b --- /dev/null +++ b/cmake/elfinfo/src/main/java/io/trygvis/ld/CollectingErrorListener.java @@ -0,0 +1,17 @@ +package io.trygvis.ld; + +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; + +import java.util.ArrayList; +import java.util.List; + +public class CollectingErrorListener extends BaseErrorListener { + public final List<String> errors = new ArrayList<>(); + + public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + String s = line + ":" + charPositionInLine + " " + msg; + errors.add(s); + } +} diff --git a/cmake/elfinfo/src/main/java/io/trygvis/ld/LdScript.java b/cmake/elfinfo/src/main/java/io/trygvis/ld/LdScript.java index f827a8b..f3c93ac 100644 --- a/cmake/elfinfo/src/main/java/io/trygvis/ld/LdScript.java +++ b/cmake/elfinfo/src/main/java/io/trygvis/ld/LdScript.java @@ -1,12 +1,14 @@ package io.trygvis.ld; -import io.trygvis.ld.antlr.GnuLdBaseVisitor; import io.trygvis.ld.antlr.GnuLdLexer; import io.trygvis.ld.antlr.GnuLdParser; +import io.trygvis.ld.antlr.GnuLdParserBaseVisitor; import org.antlr.v4.runtime.ANTLRFileStream; import org.antlr.v4.runtime.BufferedTokenStream; +import org.antlr.v4.runtime.ConsoleErrorListener; import org.antlr.v4.runtime.tree.ParseTreeProperty; +import java.io.File; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashSet; @@ -15,6 +17,12 @@ import java.util.Set; public class LdScript { + public final List<MemoryArea> memoryAreas; + + public LdScript(List<MemoryArea> memoryAreas) { + this.memoryAreas = memoryAreas; + } + public enum MemoryAttribute { R, W, X, A, I, } @@ -76,39 +84,31 @@ public class LdScript { String name; } - public static void main(String[] args) throws Exception { - try { - work(args); - } catch (Exception e) { - e.printStackTrace(System.out); - } - } - - private static void work(String[] args) throws Exception { - args = new String[]{"lds/d2000.ld"}; + public static LdScript parse(File path) throws Exception { + GnuLdLexer lexer = new GnuLdLexer(new ANTLRFileStream(path.getAbsolutePath())); + BufferedTokenStream tokens = new BufferedTokenStream(lexer); + GnuLdParser parser = new GnuLdParser(tokens); + parser.setBuildParseTree(true); + parser.removeErrorListeners(); + ConsoleErrorListener errorListener = new ConsoleErrorListener(); + parser.addErrorListener(errorListener); + CollectingErrorListener collectingErrorListener = new CollectingErrorListener(); + parser.addErrorListener(collectingErrorListener); - GnuLdLexer lexer = new GnuLdLexer(new ANTLRFileStream(args[0])); - GnuLdParser parser = new GnuLdParser(new BufferedTokenStream(lexer)); + GnuLdParser.FileContext file = parser.file(); -// ElfInfoGnuLdBaseListener listener = new ElfInfoGnuLdBaseListener(); -// parser.addParseListener(listener); -// -// parser.file(); -// -// for (Section section : listener.sections) { -// System.out.println("section.name = " + section.name); -// } + if (parser.getNumberOfSyntaxErrors() > 0) { + throw new ParseErrorException(lexer, tokens, parser, collectingErrorListener.errors + ); + } ElfinfoGnuLdBaseVisitor visitor = new ElfinfoGnuLdBaseVisitor(); - visitor.visit(parser.file()); + visitor.visit(file); - System.out.println("--------------------------------------------------------"); - for (MemoryArea area : visitor.memoryAreas) { - System.out.println(" " + area.name + "(" + area.prettyAttributes() + ") : ORIGIN = " + area.prettyOrigin() + ", LENGTH=" + area.prettyLength()); - } + return new LdScript(visitor.memoryAreas); } - private static class ElfinfoExprGnuLdBaseVisitor extends GnuLdBaseVisitor<ElfinfoExprGnuLdBaseVisitor> { + private static class ElfinfoExprGnuLdBaseVisitor extends GnuLdParserBaseVisitor<ElfinfoExprGnuLdBaseVisitor> { private BigInteger value; private ParseTreeProperty<BigInteger> es = new ParseTreeProperty<>(); @@ -227,7 +227,7 @@ public class LdScript { } @Override - public ElfinfoExprGnuLdBaseVisitor visitExpAlign2(GnuLdParser.ExpAlign2Context ctx) { + public ElfinfoExprGnuLdBaseVisitor visitExpAlignK(GnuLdParser.ExpAlignKContext ctx) { return visitChildren(ctx); } @@ -416,7 +416,7 @@ public class LdScript { } } - private static class ElfinfoGnuLdBaseVisitor extends GnuLdBaseVisitor<ElfinfoGnuLdBaseVisitor> { + public static class ElfinfoGnuLdBaseVisitor extends GnuLdParserBaseVisitor<ElfinfoGnuLdBaseVisitor> { public List<MemoryArea> memoryAreas = new ArrayList<>(); public List<Section> sections = new ArrayList<>(); @@ -473,6 +473,7 @@ public class LdScript { if (!attributes.isEmpty()) { throw new RuntimeException("Attributes for memory areas can only be attributesInverted (with '!') as the first character in a specification; foo(!rw), not foo(x!rw)."); } +// String name = ctx.name().getText(); String name = ctx.NAME().getText(); System.out.println("ctx.ATTRIBUTE().getText() = " + name); @@ -480,4 +481,18 @@ public class LdScript { return visitChildren(ctx); } } + + public static class ParseErrorException extends Exception { + public final GnuLdLexer lexer; + public final BufferedTokenStream tokens; + public final GnuLdParser parser; + public final List<String> errors; + + public ParseErrorException(GnuLdLexer lexer, BufferedTokenStream tokens, GnuLdParser parser, List<String> errors) { + this.lexer = lexer; + this.tokens = tokens; + this.parser = parser; + this.errors = errors; + } + } } diff --git a/cmake/elfinfo/src/main/java/io/trygvis/ld/StringGnuLdVisitor.java b/cmake/elfinfo/src/main/java/io/trygvis/ld/StringGnuLdVisitor.java new file mode 100644 index 0000000..a975497 --- /dev/null +++ b/cmake/elfinfo/src/main/java/io/trygvis/ld/StringGnuLdVisitor.java @@ -0,0 +1,59 @@ +package io.trygvis.ld; + +import io.trygvis.ld.antlr.GnuLdParserBaseVisitor; +import io.trygvis.ld.antlr.GnuLdParser; +import org.antlr.v4.runtime.tree.ParseTree; + +import java.util.List; + +class StringGnuLdVisitor extends GnuLdParserBaseVisitor<String> { + +// public static String parseName(GnuLdParser.NameContext ctx) { +// return ""; +// } + + /* + public static String parseName(GnuLdParser.NameContext ctx) { + StringGnuLdVisitor v = new StringGnuLdVisitor(); + return v.visit(ctx); + } + + private StringBuilder string = new StringBuilder(); + + @Override + public String visitNamePlain(GnuLdParser.NamePlainContext ctx) { + System.out.println("NameTest.visitNamePlain"); + String s = ctx.NAME().getText(); + string.append(s); + return s; + } + +// @Override +// public String visitName_or_space(GnuLdParser.Name_or_spaceContext ctx) { +// System.out.println("StringGnuLdBaseVisitor.visitName_or_space"); +// +// TerminalNode name = ctx.NAME(); +// String s = name != null ? name.getText() : " "; +// string.append(s); +// return s; +// } + + @Override + public String visitNameQuoted(GnuLdParser.NameQuotedContext ctx) { + System.out.println("StringGnuLdBaseVisitor.visitNameQuoted"); + List<ParseTree> children = ctx.children; + System.out.println("children.size()) = " + children.size()); + + String s = ""; + for (int i = 1; i < children.size() - 1; i++) { + ParseTree part = children.get(i); + System.out.println("part.getText() = " + part.getText()); + s += part.getText(); + } + + return s; +// +// return visitChildren(ctx); + } + */ +} diff --git a/cmake/elfinfo/src/main/test/io/trygvis/ld/FullScriptsTest.java b/cmake/elfinfo/src/main/test/io/trygvis/ld/FullScriptsTest.java new file mode 100644 index 0000000..1452f1f --- /dev/null +++ b/cmake/elfinfo/src/main/test/io/trygvis/ld/FullScriptsTest.java @@ -0,0 +1,34 @@ +package io.trygvis.ld; + +import io.trygvis.ld.test1.Test1Test; +import org.junit.Test; + +import java.io.File; + +public class FullScriptsTest { + + @Test + public void testD2000() throws Exception { + fullScript2("lds/d2000.ld"); + } + + @Test + public void testStm32() throws Exception { + fullScript2("lds/stm32.ld"); + } + + private void fullScript2(String fileName) throws Exception { + try { + LdScript script = LdScript.parse(new File(fileName)); + + System.out.println("--------------------------------------------------------"); + for (LdScript.MemoryArea area : script.memoryAreas) { + System.out.println(" " + area.name + "(" + area.prettyAttributes() + ") : ORIGIN = " + area.prettyOrigin() + ", LENGTH=" + area.prettyLength()); + } + } catch (LdScript.ParseErrorException e) { + Test1Test.showTokens(e.tokens, e.parser); + System.out.println("Got " + e.errors.size() + " errors:"); + e.errors.forEach(System.out::println); + } + } +} diff --git a/cmake/elfinfo/src/main/test/io/trygvis/ld/InputSectionSpecTest.java b/cmake/elfinfo/src/main/test/io/trygvis/ld/InputSectionSpecTest.java new file mode 100644 index 0000000..2950061 --- /dev/null +++ b/cmake/elfinfo/src/main/test/io/trygvis/ld/InputSectionSpecTest.java @@ -0,0 +1,38 @@ +package io.trygvis.ld; + +import io.trygvis.ld.antlr.GnuLdLexer; +import io.trygvis.ld.antlr.GnuLdParser; +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class InputSectionSpecTest { + @Test + public void testName1() throws Exception { + a("*(.text)", "(input_section_spec (input_section_spec_no_keep (wildcard_spec (wildcard_name *)) ( (file_name_list (wildcard_spec (wildcard_name .text))) )))"); + } + + // This doesn't feel right + @Test + public void testName2() throws Exception { + a("*(.text.*)", "(input_section_spec (input_section_spec_no_keep (wildcard_spec (wildcard_name *)) ( (file_name_list (file_name_list (wildcard_spec (wildcard_name .text.))) opt_comma (wildcard_spec (wildcard_name *))) )))"); + } + + @Test + public void testName3() throws Exception { + a("KEEP(*/init_high.cpp.obj(.isr_vectors))", "(input_section_spec KEEP ( (input_section_spec_no_keep (wildcard_spec (wildcard_name *)) / init_high.cpp.obj ( .isr_vectors) ))"); + } + + private void a(String input, String expected) { + GnuLdParser parser = new GnuLdParser(new CommonTokenStream(new GnuLdLexer(new ANTLRInputStream(input)))); + parser.setBuildParseTree(true); + parser.removeErrorListeners(); + parser.addErrorListener(new SystemOutReportingErrorListener(input)); + GnuLdParser.Input_section_specContext input_section_spec = parser.input_section_spec(); + + assertEquals(input, expected, input_section_spec.toStringTree(parser)); + assertEquals(0, parser.getNumberOfSyntaxErrors()); + } +} diff --git a/cmake/elfinfo/src/main/test/io/trygvis/ld/NameTest.java b/cmake/elfinfo/src/main/test/io/trygvis/ld/NameTest.java new file mode 100644 index 0000000..8d7502f --- /dev/null +++ b/cmake/elfinfo/src/main/test/io/trygvis/ld/NameTest.java @@ -0,0 +1,50 @@ +package io.trygvis.ld; + +import io.trygvis.ld.antlr.GnuLdLexer; +import io.trygvis.ld.antlr.GnuLdParser; +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class NameTest { + @Test + public void testName1() throws Exception { + a("foo", "foo"); + } + + @Test + public void testName2() throws Exception { + a("\"foo bar\"", "foo bar"); + } + + // TODO: not really expected + @Test + public void testName3() throws Exception { + a("\"foo bar\"", "foo bar"); + } + + private void a(String input, String expected) { + /* + CommonTokenStream tokens = new CommonTokenStream(new GnuLdLexer(new ANTLRInputStream(input))); + tokens.fill(); + for (Object tok : tokens.getTokens()) { + System.out.println(tok); + } + GnuLdParser parser = new GnuLdParser(tokens); + +// StringGnuLdVisitor visitor = new StringGnuLdVisitor(); + GnuLdParser.NameContext name = parser.name(); + + System.out.println("Input : |" + input + "|"); + System.out.println("String tree: " + name.toStringTree(parser)); + +// visitor.visit(name); + String actual = StringGnuLdVisitor.parseName(name); + + parser.setTrace(true); + assertEquals(input + "\n" + name.toStringTree(), expected, actual); + */ + } +} diff --git a/cmake/elfinfo/src/main/test/io/trygvis/ld/SystemOutReportingErrorListener.java b/cmake/elfinfo/src/main/test/io/trygvis/ld/SystemOutReportingErrorListener.java new file mode 100644 index 0000000..c21a2e2 --- /dev/null +++ b/cmake/elfinfo/src/main/test/io/trygvis/ld/SystemOutReportingErrorListener.java @@ -0,0 +1,32 @@ +package io.trygvis.ld; + +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class SystemOutReportingErrorListener extends BaseErrorListener { + @Nullable + private final String input; + + public SystemOutReportingErrorListener(@Nonnull String input) { + this.input = input; + } + + public SystemOutReportingErrorListener() { + input = null; + } + + public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + System.out.println("line " + line + ":" + charPositionInLine + " " + msg); + if (input != null) { + System.out.println(input); + for (int i = 1; i < charPositionInLine; i++) { + System.out.print(' '); + } + } + System.out.println('^'); + } +} diff --git a/cmake/elfinfo/src/main/test/io/trygvis/ld/test1/Test1Test.java b/cmake/elfinfo/src/main/test/io/trygvis/ld/test1/Test1Test.java new file mode 100644 index 0000000..ca3f49a --- /dev/null +++ b/cmake/elfinfo/src/main/test/io/trygvis/ld/test1/Test1Test.java @@ -0,0 +1,102 @@ +package io.trygvis.ld.test1; + +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.BufferedTokenStream; +import org.antlr.v4.runtime.CommonToken; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.Token; +import org.junit.Test; + +import javax.annotation.Nonnull; + +import static org.junit.Assert.assertEquals; + +public class Test1Test { + + @Test + public void test1() { + name("foo", "foo"); + } + + @Test + public void test2() { + name("\"foo bar\"", "foo bar"); + } + + private void name(String input, String expected) { + Test1Parser parser = load(input); + + Test1Parser.NameContext name = parser.name(); + System.out.println("String tree: " + name.toStringTree(parser)); + + String actual = name.getText(); + assertEquals(input + "\n" + name.toStringTree(parser), expected, actual); + } + + @Test + public void expr1() { + expr("a + b", "(expr (name a) + (name b))"); + } + + @Test + public void expr2() { + expr("\"foo bar\" + b", "(expr (name f o o b a r) + (name b))"); + } + + @Test + public void expr3() { + expr("\n\n\r\n\t\"foo bar\" + b\r\r\t", "(expr (name f o o b a r) + (name b))"); + } + + private void expr(String input, String expected) { + Test1Parser parser = load(input); + + Test1Parser.ExprContext expr = parser.expr(); + String stringTree = expr.toStringTree(parser); + + assertEquals(expected, stringTree); + } + + @Nonnull + private Test1Parser load(String input) { + System.out.println("Input : |" + input + "|"); + CommonTokenStream tokens = new CommonTokenStream(new Test1Lexer(new ANTLRInputStream(input))); + Test1Parser parser = new Test1Parser(tokens); + parser.setBuildParseTree(true); + parser.setTrace(true); + + tokens.fill(); + showTokens(tokens, parser); + return parser; + } + + public static void showTokens(BufferedTokenStream tokens, Parser parser) { + for (Token tok : tokens.getTokens()) { + String s; + if (tok instanceof CommonToken) { + CommonToken t = (CommonToken) tok; + + String channelStr = ""; + if (t.getChannel() > 0) { + channelStr = ",channel=" + t.getChannel(); + } + + String txt = t.getText(); + if (txt != null) { + txt = txt.replace("\n", "\\n"); + txt = txt.replace("\r", "\\r"); + txt = txt.replace("\t", "\\t"); + } else { + txt = "<no text>"; + } + + String type = parser.getVocabulary().getDisplayName(t.getType()); + s = "[@" + t.getTokenIndex() + "," + t.getStartIndex() + ":" + t.getStopIndex() + "=\'" + txt + "\',<" + type + ">" + channelStr + "," + t.getLine() + ":" + t.getCharPositionInLine() + "]"; + } else { + s = tok.toString(); + } + System.out.println(s); + } + } +} |