1 /* 2 * [The "BSD license"] 3 * Copyright (c) 2010 Terence Parr 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 31 Please excuse my obvious lack of Java experience. The code here is probably 32 full of WTFs - though IMHO Java is the Real WTF(TM) here... 33 34 */ 35 36 package org.antlr.codegen; 37 38 import org.antlr.runtime.Token; 39 import org.antlr.tool.Grammar; 40 41 import java.util.ArrayList; 42 import java.util.List; 43 44 public class PythonTarget extends Target { 45 /** Target must be able to override the labels used for token types */ getTokenTypeAsTargetLabel(CodeGenerator generator, int ttype)46 public String getTokenTypeAsTargetLabel(CodeGenerator generator, 47 int ttype) { 48 // use ints for predefined types; 49 // <invalid> <EOR> <DOWN> <UP> 50 if ( ttype >= 0 && ttype <= 3 ) { 51 return String.valueOf(ttype); 52 } 53 54 String name = generator.grammar.getTokenDisplayName(ttype); 55 56 // If name is a literal, return the token type instead 57 if ( name.charAt(0)=='\'' ) { 58 return String.valueOf(ttype); 59 } 60 61 return name; 62 } 63 getTargetCharLiteralFromANTLRCharLiteral( CodeGenerator generator, String literal)64 public String getTargetCharLiteralFromANTLRCharLiteral( 65 CodeGenerator generator, 66 String literal) { 67 int c = Grammar.getCharValueFromGrammarCharLiteral(literal); 68 return String.valueOf(c); 69 } 70 splitLines(String text)71 private List splitLines(String text) { 72 ArrayList l = new ArrayList(); 73 int idx = 0; 74 75 while ( true ) { 76 int eol = text.indexOf("\n", idx); 77 if ( eol == -1 ) { 78 l.add(text.substring(idx)); 79 break; 80 } 81 else { 82 l.add(text.substring(idx, eol+1)); 83 idx = eol+1; 84 } 85 } 86 87 return l; 88 } 89 postProcessAction(List chunks, Token actionToken)90 public List postProcessAction(List chunks, Token actionToken) { 91 /* TODO 92 - check for and report TAB usage 93 */ 94 95 //System.out.println("\n*** Action at " + actionToken.getLine() + ":" + actionToken.getColumn()); 96 97 /* First I create a new list of chunks. String chunks are splitted into 98 lines and some whitespace my be added at the beginning. 99 100 As a result I get a list of chunks 101 - where the first line starts at column 0 102 - where every LF is at the end of a string chunk 103 */ 104 105 List nChunks = new ArrayList(); 106 for (int i = 0; i < chunks.size(); i++) { 107 Object chunk = chunks.get(i); 108 109 if ( chunk instanceof String ) { 110 String text = (String)chunks.get(i); 111 if ( nChunks.size() == 0 && actionToken.getCharPositionInLine() >= 0 ) { 112 // first chunk and some 'virtual' WS at beginning 113 // prepend to this chunk 114 115 String ws = ""; 116 for ( int j = 0 ; j < actionToken.getCharPositionInLine() ; j++ ) { 117 ws += " "; 118 } 119 text = ws + text; 120 } 121 122 List parts = splitLines(text); 123 for ( int j = 0 ; j < parts.size() ; j++ ) { 124 chunk = parts.get(j); 125 nChunks.add(chunk); 126 } 127 } 128 else { 129 if ( nChunks.size() == 0 && actionToken.getCharPositionInLine() >= 0 ) { 130 // first chunk and some 'virtual' WS at beginning 131 // add as a chunk of its own 132 133 String ws = ""; 134 for ( int j = 0 ; j <= actionToken.getCharPositionInLine() ; j++ ) { 135 ws += " "; 136 } 137 nChunks.add(ws); 138 } 139 140 nChunks.add(chunk); 141 } 142 } 143 144 int lineNo = actionToken.getLine(); 145 int col = 0; 146 147 // strip trailing empty lines 148 int lastChunk = nChunks.size() - 1; 149 while ( lastChunk > 0 150 && nChunks.get(lastChunk) instanceof String 151 && ((String)nChunks.get(lastChunk)).trim().length() == 0 ) 152 lastChunk--; 153 154 // string leading empty lines 155 int firstChunk = 0; 156 while ( firstChunk <= lastChunk 157 && nChunks.get(firstChunk) instanceof String 158 && ((String)nChunks.get(firstChunk)).trim().length() == 0 159 && ((String)nChunks.get(firstChunk)).endsWith("\n") ) { 160 lineNo++; 161 firstChunk++; 162 } 163 164 int indent = -1; 165 for ( int i = firstChunk ; i <= lastChunk ; i++ ) { 166 Object chunk = nChunks.get(i); 167 168 //System.out.println(lineNo + ":" + col + " " + quote(chunk.toString())); 169 170 if ( chunk instanceof String ) { 171 String text = (String)chunk; 172 173 if ( col == 0 ) { 174 if ( indent == -1 ) { 175 // first non-blank line 176 // count number of leading whitespaces 177 178 indent = 0; 179 for ( int j = 0; j < text.length(); j++ ) { 180 if ( !Character.isWhitespace(text.charAt(j)) ) 181 break; 182 183 indent++; 184 } 185 } 186 187 if ( text.length() >= indent ) { 188 int j; 189 for ( j = 0; j < indent ; j++ ) { 190 if ( !Character.isWhitespace(text.charAt(j)) ) { 191 // should do real error reporting here... 192 System.err.println("Warning: badly indented line " + lineNo + " in action:"); 193 System.err.println(text); 194 break; 195 } 196 } 197 198 nChunks.set(i, text.substring(j)); 199 } 200 else if ( text.trim().length() > 0 ) { 201 // should do real error reporting here... 202 System.err.println("Warning: badly indented line " + lineNo + " in action:"); 203 System.err.println(text); 204 } 205 } 206 207 if ( text.endsWith("\n") ) { 208 lineNo++; 209 col = 0; 210 } 211 else { 212 col += text.length(); 213 } 214 } 215 else { 216 // not really correct, but all I need is col to increment... 217 col += 1; 218 } 219 } 220 221 return nChunks; 222 } 223 } 224