PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/compiler/org/pshdl/model/parser/PSHDLParser.java

https://bitbucket.org/kbecker/pshdl
Java | 244 lines | 179 code | 16 blank | 49 comment | 37 complexity | 3a10ce9771f212e9e74a4d570460f2ba MD5 | raw file
  1. /*******************************************************************************
  2. * PSHDL is a library and (trans-)compiler for PSHDL input. It generates
  3. * output suitable for implementation or simulation of it.
  4. *
  5. * Copyright (C) 2013 Karsten Becker (feedback (at) pshdl (dot) org)
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. * This License does not grant permission to use the trade names, trademarks,
  21. * service marks, or product names of the Licensor, except as required for
  22. * reasonable and customary use in describing the origin of the Work.
  23. *
  24. * Contributors:
  25. * Karsten Becker - initial API and implementation
  26. ******************************************************************************/
  27. package org.pshdl.model.parser;
  28. import java.io.BufferedReader;
  29. import java.io.File;
  30. import java.io.FileInputStream;
  31. import java.io.FileNotFoundException;
  32. import java.io.IOException;
  33. import java.io.InputStream;
  34. import java.io.InputStreamReader;
  35. import java.nio.charset.StandardCharsets;
  36. import java.util.ArrayList;
  37. import java.util.List;
  38. import java.util.Set;
  39. import org.antlr.v4.runtime.ANTLRErrorListener;
  40. import org.antlr.v4.runtime.BaseErrorListener;
  41. import org.antlr.v4.runtime.CharStream;
  42. import org.antlr.v4.runtime.CharStreams;
  43. import org.antlr.v4.runtime.CommonTokenStream;
  44. import org.antlr.v4.runtime.FailedPredicateException;
  45. import org.antlr.v4.runtime.InputMismatchException;
  46. import org.antlr.v4.runtime.LexerNoViableAltException;
  47. import org.antlr.v4.runtime.NoViableAltException;
  48. import org.antlr.v4.runtime.RecognitionException;
  49. import org.antlr.v4.runtime.Recognizer;
  50. import org.antlr.v4.runtime.Token;
  51. import org.pshdl.model.HDLExpression;
  52. import org.pshdl.model.HDLPackage;
  53. import org.pshdl.model.evaluation.HDLEvaluationContext;
  54. import org.pshdl.model.parser.PSHDLLang.PsExpressionContext;
  55. import org.pshdl.model.parser.PSHDLLang.PsModelContext;
  56. import org.pshdl.model.utils.HDLLibrary;
  57. import org.pshdl.model.utils.services.IHDLValidator.IErrorCode;
  58. import org.pshdl.model.validation.Problem;
  59. import org.pshdl.model.validation.Problem.ProblemSeverity;
  60. public class PSHDLParser {
  61. public static String[] getKeywords() throws Exception {
  62. final InputStream resourceAsStream = PSHDLParser.class.getResourceAsStream("PSHDLLangLexer.tokens");
  63. try (final BufferedReader reader = new BufferedReader(new InputStreamReader(resourceAsStream, StandardCharsets.UTF_8))) {
  64. String line = null;
  65. final List<String> keywords = new ArrayList<>();
  66. while ((line = reader.readLine()) != null) {
  67. if (line.charAt(0) == '\'') {
  68. final String keyWord = line.substring(1, line.lastIndexOf('\''));
  69. if (keyWord.matches("[a-z]+")) {
  70. keywords.add(keyWord);
  71. }
  72. }
  73. }
  74. return keywords.toArray(new String[keywords.size()]);
  75. }
  76. }
  77. public static HDLPackage parse(File file, String libURI, Set<Problem> syntaxProblems, HDLEvaluationContext context) throws IOException, FileNotFoundException {
  78. try (final FileInputStream fis = new FileInputStream(file)) {
  79. final HDLPackage hdl = parseStream(CharStreams.fromStream(fis), libURI, syntaxProblems, file.getAbsolutePath(), context);
  80. return hdl;
  81. }
  82. }
  83. public static final class SyntaxErrorCollector extends BaseErrorListener {
  84. private final Set<Problem> syntaxProblems;
  85. private final CommonTokenStream ts;
  86. private int lineOffset = 0;
  87. public SyntaxErrorCollector(CommonTokenStream ts, Set<Problem> syntaxProblems) {
  88. this.syntaxProblems = syntaxProblems;
  89. this.ts = ts;
  90. }
  91. public SyntaxErrorCollector(CommonTokenStream tokens, Set<Problem> problems, int lineOffset) {
  92. this(tokens, problems);
  93. this.lineOffset = lineOffset;
  94. }
  95. @Override
  96. public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
  97. int length = -1;
  98. int totalOffset = -1;
  99. SyntaxErrors error = SyntaxErrors.OtherException;
  100. if ((e == null) && PSHDLLang.MISSING_SEMI.equals(msg)) {
  101. error = SyntaxErrors.MissingSemicolon;
  102. msg = "Missing ';'";
  103. }
  104. if ((e == null) && PSHDLLang.WRONG_ORDER.equals(msg)) {
  105. error = SyntaxErrors.WrongOrder;
  106. msg = "The order for variable declarations is «direction?» «register?» «type» «name»";
  107. }
  108. if ((e == null) && PSHDLLang.MISSING_WIDTH.equals(msg)) {
  109. error = SyntaxErrors.MissingWidth;
  110. msg = "The empty width <> is only allowed in function declarations";
  111. }
  112. if ((e == null) && PSHDLLang.MISSING_TYPE.equals(msg)) {
  113. error = SyntaxErrors.MissingType;
  114. msg = "The variable declaration is missing its type";
  115. }
  116. if ((e == null) && PSHDLLang.MISSING_IFPAREN.equals(msg)) {
  117. error = SyntaxErrors.MissingIfParen;
  118. msg = "The syntax for if-statements is 'if («expression») { «thenStatements*» } else { «elseStatements*» }";
  119. }
  120. if (offendingSymbol instanceof Token) {
  121. Token t = (Token) offendingSymbol;
  122. if (error == SyntaxErrors.MissingSemicolon) {
  123. do {
  124. t = ts.get(t.getTokenIndex() - 1);
  125. } while (t.getChannel() != 0);
  126. line = t.getLine();
  127. charPositionInLine = t.getCharPositionInLine();
  128. }
  129. totalOffset = t.getStartIndex();
  130. final String text = t.getText();
  131. if (text != null) {
  132. length = text.length();
  133. }
  134. }
  135. if (e instanceof NoViableAltException) {
  136. final NoViableAltException noVi = (NoViableAltException) e;
  137. error = SyntaxErrors.NoViableAlternative;
  138. final Token t = noVi.getStartToken();
  139. charPositionInLine = t.getCharPositionInLine();
  140. line = t.getLine();
  141. totalOffset = t.getStartIndex();
  142. final String text = t.getText();
  143. if (text != null) {
  144. length = text.length();
  145. }
  146. }
  147. if (e instanceof LexerNoViableAltException) {
  148. error = SyntaxErrors.LexerNoViableAlternative;
  149. }
  150. if (e instanceof InputMismatchException) {
  151. error = SyntaxErrors.InputMismatch;
  152. }
  153. if (e instanceof FailedPredicateException) {
  154. error = SyntaxErrors.FailedPredicate;
  155. }
  156. line += lineOffset;
  157. syntaxProblems.add(new Problem(error, msg, line, charPositionInLine, length, totalOffset));
  158. }
  159. }
  160. public static enum SyntaxErrors implements IErrorCode {
  161. FailedPredicate, NoViableAlternative, LexerNoViableAlternative, InputMismatch, OtherException, MissingSemicolon, MissingType, WrongOrder, MissingWidth, MissingIfParen;
  162. @Override
  163. public ProblemSeverity getSeverity() {
  164. return ProblemSeverity.ERROR;
  165. }
  166. }
  167. /**
  168. * Parses the given input String and generates a output {@link HDLPackage} if it succeed
  169. *
  170. * @param input
  171. * the String to parse and convert
  172. * @param libURI
  173. * the library URI to retrieve a registered {@link HDLLibrary}
  174. * @param syntaxProblems
  175. * a HashSet where syntax problems will be added to
  176. * @param src
  177. * the resource from which this String was derived
  178. * @param context
  179. * @return a {@link HDLPackage} if successful, <code>null</code>l otherwise
  180. */
  181. public static HDLPackage parseString(String input, String libURI, final Set<Problem> syntaxProblems, String src, HDLEvaluationContext context) {
  182. return parseStream(CharStreams.fromString(input), libURI, syntaxProblems, src, context);
  183. }
  184. private static HDLPackage parseStream(CharStream input, String libURI, final Set<Problem> syntaxProblems, String src, HDLEvaluationContext context) {
  185. final PSHDLLangLexer lexer = new PSHDLLangLexer(input);
  186. final CommonTokenStream tokens = new CommonTokenStream(lexer);
  187. final PSHDLLang parser = new PSHDLLang(tokens);
  188. final ANTLRErrorListener listener = new SyntaxErrorCollector(tokens, syntaxProblems);
  189. lexer.removeErrorListeners();
  190. lexer.addErrorListener(listener);
  191. parser.removeErrorListeners();
  192. parser.addErrorListener(listener);
  193. final PsModelContext psModel = parser.psModel();
  194. if (syntaxProblems.size() == 0) {
  195. final HDLPackage hdl = ParserToModelExtension.toHDL(tokens, psModel, libURI, src, context);
  196. return hdl;
  197. }
  198. return null;
  199. }
  200. /**
  201. * Parses the given input String and generates a output {@link HDLPackage} if it succeed
  202. *
  203. * @param input
  204. * the String to parse and convert
  205. * @param syntaxProblems
  206. * a HashSet where syntax problems will be added to
  207. * @return a {@link HDLPackage} if successful, <code>null</code>l otherwise
  208. */
  209. public static HDLExpression parseExpressionString(String input, final Set<Problem> syntaxProblems) {
  210. return parseExpressionStream(CharStreams.fromString(input), syntaxProblems);
  211. }
  212. private static HDLExpression parseExpressionStream(CharStream input, final Set<Problem> syntaxProblems) {
  213. final PSHDLLangLexer lexer = new PSHDLLangLexer(input);
  214. final CommonTokenStream tokens = new CommonTokenStream(lexer);
  215. final ANTLRErrorListener parserListener = new SyntaxErrorCollector(tokens, syntaxProblems);
  216. final PSHDLLang parser = new PSHDLLang(tokens);
  217. parser.removeErrorListeners();
  218. parser.addErrorListener(parserListener);
  219. lexer.removeErrorListeners();
  220. lexer.addErrorListener(parserListener);
  221. final PsExpressionContext psExpression = parser.psExpression();
  222. if (syntaxProblems.size() == 0) {
  223. final HDLExpression hdl = ParserToModelExtension.toHDLExpression(tokens, psExpression);
  224. return hdl;
  225. }
  226. return null;
  227. }
  228. }