How to extract token information from attribute "elements"? - antlr3

1. Overall Task:
I want to customize the Java.stg to modify the token display format in the comment of the code block for an alternative of grammar rule.
2. Context:
one rule in my current grammar is:
temporal returns [String ret]:
NEXT disj
{$ret= $ret= "X ".concat($disj.ret);}
| EVENTUALLY disj
{$ret= "F ".concat($disj.ret);}`
;
The corresponding generated code block (in parser) is as follows:
switch (alt2) {
case 1 :
// RERS.g:26:7: NEXT disj
{
match(input,NEXT,FOLLOW_NEXT_in_temporal204);
pushFollow(FOLLOW_disj_in_temporal206);
disj2=disj();
state._fsp--;
ret = ret = "X ".concat(disj2);
}
break;
case 2 :
// RERS.g:28:7: EVENTUALLY disj
{
match(input,EVENTUALLY,FOLLOW_EVENTUALLY_in_temporal222);
pushFollow(FOLLOW_disj_in_temporal224);
disj3=disj();
state._fsp--;
ret = "F ".concat(disj3);
}
break;
3. My Goal:
Change the comment from format like // RERS.g:26:7: NEXT disj to NEXT_disj, i.e., from <fileName>:<description> to <MyOwnAttribute>
4. Attempt so far:
I tried to modify the template "alt(elements,altNum,description,autoAST,outerAlt,treeLevel,rew)" as follows:
alt(elements,altNum,description,autoAST,outerAlt,treeLevel,rew) ::= <<
/* <elements:ExtractToken()> */
{
<#declarations()>
<elements:element()> // as I understand, it's just an template expansion to apply the sub templates in each elements
<rew>
<#cleanup()>
}
>>
I checked that in this context, the value of attribute elements is something like {el=/tokenRef(), line=26, pos=7}{el=/ruleRef(), line=26, pos=12}{el=/execAction(), line=27, pos=7}.
I think I should "overload" the "tokenRef" template to spit out tokens formatted like "NEXT_disj"
5. Questions:
How to "overload" an existing template? I want to do that because I will have to modify the value of "elements" otherwise.
How can I only apply a template to a specific element in attribute "elements", instead of applying it to every element (like what template "element()" does)?
I think there should be some convenient way to achieve my goal. Any suggestion?
Thanks in advance.

Related

How can I parse this plaintext RP-style string into a more generic XML-style one?

I'm making an app that will translate roleplaying-style messages into something much more generic. The user has the ability to specify their preferences, like:
Moves
- /me <move>
- *<move>*
Speech
- <speech>
- "<speech>"
Out-of-Character
- [<ooc>]
- ((ooc))
- //ooc
I need to parse a message like this:
/me eats food "This is *munch* good!" [You're good at this]
or like this:
*eats food* This is *munch* good! ((You're good at this))
into a more generic, XML-like string like this:
<move>eats food <speech>This is <move>munch</move> good!</speech> <ooc>You're good at this</ooc></move>
but with regard to which is inside which. For example:
*eats food "This is munch* good" // You're good at this
should be parsed as:
<move>eats food "This is munch</move><speech> good" </speech><ooc> You're good at this</ooc>
even if that's not what the user intended. Note that the quotes in this last example weren't parsed because they didn't wrap a complete segment, and the current move segment had not finished by the time the first was encountered, and speech had already started when the second one was, and the second one didn't have another after it to surround a separate speech segment.
I've tried doing this iteratively, recursively, with trees, and even with regexes, but I haven't found a solution that works like I want it to. How do I parse the above RP-style messages into the above generic XML-style messages?
Also important is that the spacing is preserved.
Here are some other examples using the above-listed preferences:
I like roller coasters.
[what are you like?]
/me eats a hamburger // wanna grab lunch after this?
*jumps up and down* This ((the party)) is great!
/me performs *an action* within an action "And that's just fine [As is *an action* in ooc in speech]"
And messages /me can change contexts // at any point
[But ill-formatted ones *must be parsed] according "to* the rules"
-And text formatted in <non-specified ways> is &not treated; specially-
become:
<speech>I like roller coasters.</speech>
<ooc>what are you like?</ooc>
<move>eats a hamburger <ooc> wanna grab lunch after this?</ooc></move>
<move>jumps up and down</move><speech> This <ooc>the party</ooc> is great!</speech>
<move>performs <move>an action</move> within an action <speech>And that's just fine <ooc>As is <move>an action</move> in ooc in speech</ooc></speech></move>
<speech>And messages <move>can change contexts <ooc> at any point</ooc></move></speech>
<ooc>But ill-formatted ones *must be parsed</ooc><speech> according <speech>to* the rules</speech></speech>
<speech>-And text formatted in <non-specified ways> is &not treated; specially-</speech>
What you have is a bunch of tokens that should trigger an xml tag. It is fairly straightforward to implement this using a function for each tag.
void move(){
xmlPrintWriter.println("<move>");
parse();
xmlPrintWriter.println(content);
xmlPrintWriter.println("</move>");
}
Where the parse() consumes and classifies the input text.
void parse(){
if (text.startsWith("*")) action = MOVE;
... other cases
if ( action == MOVE){
move();
}
... other actions.
The parse method has to check for all possible state-changers "*" -> move, "((" -> ooc, """ -> speech and so on.
Here MOVE is a class constant, action a state variable along with text and xmlPrintWriter. move and parse are both methods
This approach will not work though if you allow your last example. Then the situation becomes extremely hairy and would need to be decided on a case by case basis.
Something to this affect might do:
public static RPMessageSegment split(RPMessageSegment text)
{
ArrayList<RPMessageSegment> majorSegments = new ArrayPP<>();
scan: for(int i = 0, l = text.length() - 1; i < l; i++)
{
dels: for(Delimiter d : delimiters)
{
if (d.startsWith(text, i))
{
RPMessageSegment newSegment = d.extractSegment(text, i);
i += newSegment.lengthWithOriginalDelimiters();
majorSegments.add(newSegment);
continue scan;
}
}
}
if (majorSegments.length() == 1)
return majorSegments.get(0);
for(int i = 0, l = majorSegments.length(); i < l; i++)
{
majorSegments.set(i, split(majorSegments.get(i)));
}
return new RPMessageSegment(majorSegments);
}
Of course, this presumes that the referenced classes have these methods that respond as one might expect. They shouldn't be terribly hard to imagine, not to mention write.
After it's parsed into RPMessageSegments, those can easily be echoed out into strings surrounded by XML-style tags

How to remove a newline from template?

This is a repost of my question in the Google Group. Hopefully I will get some response here.
Frequently I run into this problem. I want to generate a line of text if the text is not empty. If it is empty, do not generate the line. Illustration template:
namespace #classSpec.getNamespace()
#classSpec.getComment()
class #classSpec.getName() {
...
}
If #classSpec.getComment() returns meaningful comment text, the result looks like
namespace com.example
// this is comment
class MyClass {
...
}
But if there is no comment, it will be
namespace com.example
class MyClass {
...
}
Notice the extra empty line? I do not want it. Currently the solution is to write template as
namespace #classSpec.getNamespace()
#classSpec.getComment()class #classSpec.getName() {
...
}
and make sure the getComment() will append a "\n" to the return value. This makes the template much less readable. Also, imagine I need to generate a function with multiple parameters in a for loop. If each parameter requires complex logic of template code, I need to make them all written in one line as above. Otherwise, the result file will have function like
function myFunction(
String stringParam,
Integer intParam,
Long longParam
)
The core problem is, the template file does not only contain scripts, but also raw text to be written in the output. For script part, we want newlines and indentations. We want the space to be trimmed just like what compilers usually do. But for raw text, we want the spaces to be exact as specified in the file. I feel we need a bit more raw text control mechanism to reconcile the two parts.
Specific to this case, is there some special symbol to treat multiple lines as single line in the output? For example, like if we can write
namespace #classSpec.getNamespace()
#classSpec.getComment()\\
class #classSpec.getName() {
...
}
Thanks!
This is just a known bug see
https://github.com/greenlaw110/Rythm/issues/259.
https://github.com/greenlaw110/Rythm/issues/232
Unfortunately there is no proper work-around for this yet. You might want to add your comments to the bugs above and reference your question.
Take the example below which you can try out at http://fiddle.rythmengine.org/#/editor
#def setXTimesY(int x,int y) { #{ int result=x*y;} #(result)}
1
2 a=#setXTimesY(2,3)
3 b=#setXTimesY(3,5)
4 c=#setXTimesY(4,7)
5
this will properly create the output:
1
2 a= 6
3 b= 15
4 c= 28
5
now try to beautify the #def setXTimesY ...
#def setXTimesY(int x,int y) {
#{
int result=x*y;
}#(result)}
1
2 a=#setXTimesY(2,3)
3 b=#setXTimesY(3,5)
4 c=#setXTimesY(4,7)
will give a wrong result
1
2 a=(result)
3 b=(result)
4 c=(result)
#def setXTimesY(int x,int y) {
#{
int result=x*y;
} #(result)}
1
2 a=#setXTimesY(2,3)
3 b=#setXTimesY(3,5)
4 c=#setXTimesY(4,7)
is better but adds a space
So
https://github.com/greenlaw110/Rythm/issues/270
is another bug along the same lines
I'm experiencing the same problem. I've not been able to find a solution in the own Rythm.
To obtain a single line as result of processing several lines in the template, I've had to implement my own mechanism, in form of a post-processing. In the template, at the end of each line that I want to join the next one, I use a custom symbol/tag as token. Then, once the template has been processed, I replace that symbol/tag, together with the line break character(s) right after it, with an empty string.
For example, if you used a tag called "#join-next-line#", the template would look like this:
#for (Bar bar : foo.getBars()).join (", ") {
#bar.name#join-next-line#
}
It's not the perfect solution, but it has worked for me.

xpath: check if current elements position is second in order

Background:
I have an XML document with the following structure:
<body>
<section>content</section>
<section>content</section>
<section>content</section>
<section>content</section>
</body>
Using xpath I want to check if a <section> element is the second element and if so apply some function.
Question:
How do I check if a <section> element is the second element in the body element?
../section[position()=2]
If you want to know if the second element in the body is named section then you can do this:
local-name(/body/child::element()[2]) eq "section"
That will return either true or false.
However, you then asked how can you check this and if it is true, then apply some function. In XPath you cannot author your own functions you can only do that in XQuery or XSLT. So let me for a moment assume you are wishing to call a different XPath function on the value of the second element if it is a section. Here is an example of applying the lower-case function:
if(local-name(/body/child::element()[2]) eq "section")then
lower-case(/body/child::element()[2])
else()
However, this can simplified as lower-case and many other functions take a value with a minimum cardinality of zero. This means that you can just apply the function to a path expression, and if the path did not match anything then the function typically returns an empty sequence, in the same way as a path that did not match will. So, this is semantically equivalent to the above:
lower-case(/body/child::element()[2][local-name(.) eq "section"])
If you are in XQuery or XSLT and are writing your own functions, I would encourage you to write functions that will accept a minimum cardinality of zero, just like lower-case does. By doing this you can chain functions together, and if there is no input data (i.e. from a path expression that does not match anything), these is no output data. This leads to a very nice functional programming style.
Question: How do I check if a element is the second element
in the body element?
Using C#, you can utilize theXPathNodeIterator class in order to traverse the nodes data, and use its CurrentPosition property to investigate the current node position:
XPathNodeIterator.CurrentPosition
Example:
const string xmlStr = #"<body>
<section>1</section>
<section>2</section>
<section>3</section>
<section>4</section>
</body>";
using (var stream = new StringReader(xmlStr))
{
var document = new XPathDocument(stream);
XPathNavigator navigator = document.CreateNavigator();
XPathNodeIterator nodes = navigator.Select("/body/section");
if (nodes.MoveNext())
{
XPathNavigator nodesNavigator = nodes.Current;
XPathNodeIterator nodesText =
nodesNavigator.SelectDescendants(XPathNodeType.Text, false);
while (nodesText.MoveNext())
{
if (nodesText.CurrentPosition == 2)
{
//DO SOMETHING WITH THE VALUE AT THIS POSITION
var currentValue = nodesText.Current.Value;
}
}
}
}

How to replace every occurrence of a string in dataSetRow?

I have some very large rptdesign report definition files.
I would like to do something like in the example below:
<expression name="expression">dataSetRow["WORK_DESCRIPTION"].replace(new RegExp('&lt;', 'g'), '<');</expression>
But for any occurrence of string in any dataset in any cell in any row.
Is this possible to do in rptdesign?
Or is there other way to accomplish this task?
One way you could do this is to create a style (use predefined data style) and add a map to it. Put a script in first expression like:
importPackage(Packages.java.lang);
if( _jsContext.getContent().getValue() instanceof String ){
if( _jsContext.getContent().getValue() == "S18_1749" ){
_jsContext.getContent().setValue(_jsContext.getContent().getValue()+"--");
}
}
true;
This will always return true. Set the second expression to false, so the map never occurs. It is a bit ugl

Codeigniter: URI segments

How do I create an if statement saying something like this?
Basically, how do you use the URI class to determine if there is a value in any segment?
$segment = value_of_any_segment;
if($segment == 1{
do stuff
}
I know this is pretty elementary, but I don't totally understand the URI class...
Your question is a little unclear to me, but I'll try to help. Are you wondering how to determine if a particular segment exists or if it contains a specific value?
As you are probably aware, you can use the URI class to access the specific URI segments. Using yoursite.com/blog/article/123 as an example, blog is the 1st segment, article is the 2nd segment, and 123 is the 3rd segment. You access each using $this->uri->segment(n)
You then can construct if statements like this:
// if segment 2 exists ("articles" in the above example), do stuff
if ($this->uri->segment(2)) {
// do stuff
}
// if segment 3 ("123" in the above example) is equal to some value, do stuff
if ($this->uri->segment(3) == $myValue) {
// do stuff
}
Hope that helps! Let me know if not and I can elaborate or provide additional information.
Edit:
If you need to determine if a particular string appears in any segment of the URI, you can do something like this:
// get the entire URI (using our example above, this is "/blog/article/123")
$myURI = $this->uri->uri_string()
// the string we want to check the URI for
$myString = "article";
// use strpos() to search the entire URI for $myString
// also, notice we're using the "!==" operator here; see note below
if (strpos($myURI, $myString) !== FALSE) {
// "article" exists in the URI
} else {
// "article" does not exist in the URI
}
A note regarding strpos() (from the PHP documentation):
This function may return Boolean
FALSE, but may also return a
non-Boolean value which evaluates to
FALSE, such as 0 or "". Please read
the section on Booleans for more
information. Use the === operator for
testing the return value of this
function.
I hope my edit helps. Let me know if I can elaborate.

Resources