parsing experiment notes

Programmers discuss here anything related to FreeOrion programming. Primarily for the developers to discuss.

Moderator: Committer

Message
Author
User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: parsing experiment notes

#16 Post by Dilvish »

Geoff the Medio wrote:I'm a bit surprised that the error message refers only to the int_value_ref part, though, rather than something about an unnamed-rule composite, but I suppose it makes a bit of sense.
Hmm, perhaps the unnamed rule-composite simply takes the name from the last (or first or something) named rule that it has; something to keep in mind as a way to possibly get more clear messages when we encounter difficult to understand error messages. For example, with one thing I was trying, I would get something like "Expected Value label here" but it would point exactly to "Value =". That gave me a headache for a while until I gave up on the particular thing I was trying. Seeing now that it was probably just taking that name from an earlier part of the rule, I might be able to go back and figure things out.
A further few thoughts: I have worked a bit on more parser separation stuff, and one thing I tried was adding expression parsing to the simple int parser. This would mean you could do "Source.Age + 5" instead of just "Source.Age" when a simple int is expected. For the non-flexible int though, since it's mainly intended for things requiring an ID number, do you think there's any need for expression parsing?
The idea of further differentiating the ID parsing seems quite reasonable to consider, though I would steer it a little differently and suspect it's not really worth putting more time into. Right now, the simple_int parser is only used as a component of the plain int_ref parser (that was to help clear up initialization timing problems) and for ID-only situations (object IDs and empire IDs). Anyplace where ""Source.Age + 5"" could be sensible already has either the full int_ref parser or the flexible_int parser and so can handle it (or should, if it doesn't please point it out). The full int_ref parser may seem like overkill for some of those situations, particularly the statistics, but I think that at least the Mode statistic (and perhaps others) could have fairly broad suitability, and so rather than work on shifting some of those to a parser *slightly* simpler than the current int_ref, I suggest we just leave them as int_ref.

Back on the ID parser, the biggest thing that simple_int covers that IDs probably don't need is the free variable parser, but contemplating breaking out a distinct parser just to cover constants and bound variables leads me to concur with your final thought:
(Though I doubt it's worth the effort...)
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: parsing experiment notes

#17 Post by Dilvish »

Hmm, I see now that the final version that I committed for the flexible int patch wound up not using the simple int parser in as many places as I had planned-- I think I must have had to roll those changes back partway through and then forgot to redo them. So that is probably still worthwhile doing. Right now one of the experimental statistics is needing the full int ref parser, but that's a pretty artificial test case.
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: parsing experiment notes

#18 Post by Dilvish »

To recap the status detail on this error-- a portion of the statistics parser is broken. We've made a bit of headway, in that the critical piece used to deadlock on initialization, but it still crashes when it is attempted to be used. The statistics parser is composed of three subrules (for both ints and doubles)-- "statistic_1", "statistic_2" and "statistic_3". In all cases they assess something over a range of objects selected by a condition; the condition parser portion is used in other places as well and seems fine. "statistic_1" is only for Count and If. It seems to be working fine, with numerous working <int> examples. "statistic_2" is for statistics on an object property (like "Industry"); it also seems to be working fine, with a couple <double> type empire statistics examples. "statistic_3" is for statistics on a ValueRef, broken into 4 subtypes. The first two we imagine work but haven't really bothered testing because they may not even be sensible for a statistic-- they are for Constants and FreeVariable (like CurrentTurn or MaxAIAggression). The third is for BoundVariables, and empire statistics has a working example (albeit rather contrived) towards the end, assessing MAX Value = LocalCandidate.SystemID; this same example also demonstrates that the basic parsing for JumpsBetween is working. In writing this now I just realized that we haven't yet attempted coverage for statistics on expressions (like "(blah1 + 3*blah2)"), which we should probably try adding. The current 4th subgroup of "statistic_3" covers statistics on "complex" variables like the main one of current interest, JumpsBetween; this is the part that is broken, causing a segfault when the parser attempts to parse something meeting this pattern-- specifically when the statistic_3 rule tries to apply the complex_variable parser.

One of the things I've figured out was how to add a lot of debugging info into the parser, together with some additional logging in various ValueRef and Condition constructors this has helped a lot; these changes are in the attached "snapshot" patch if anyone else wants to experiment. That's how I could determine the statistic_3 failure point, the stat 3 code is

Code: Select all

    statistic_3
        =       parse::enum_parser<ValueRef::StatisticType>() [ std::cout << phx::val("trying Statistic3 type(") << _1 << phx::val(")\n") << std::flush, _b = _1 ]
            >>  parse::label(Value_token)
            >> (
                  (
                    (    constant        [_c = _1 ]  // match only a subset of ValueRef types here, because parsing as a top-level
                    |    free_variable   [_c = _1 ]  // ValueRef here causes deadlocks on parser init on some systems
                    |    bound_variable  [_c = _1 ]  // todo: try allowing parsing of complex variables here
                    )
                    >>  parse::label(Condition_token) >    parse::detail::condition_parser
                        [ std::cout << phx::val(" Statistic3 finishing after const, free or bound.\n") << std::flush, _val = new_<ValueRef::Statistic<T> >(_c, _b, _1) ])
                |   ( eps [std::cout << phx::val(" Statistic3 trying complex var.\n") << std::flush] 
                    >>  complex_variable [ std::cout << phx::val(" Statistic3 parsed complex var.\n") << std::flush, _c = _1 ]
                    >>  parse::label(Condition_token) >    parse::detail::condition_parser
                        [ _val = new_<ValueRef::Statistic<T> >(_c, _b, _1) ])
                )
        ;
For a successful parse, like for the the second Object ref of this JumpsBetween, which triggers the Statistic3 parser

Code: Select all

Statistic name = "STATISTICS_TEST_1" value =
    JumpsBetween object = source.SystemID object = MAX Value = LocalCandidate.SystemID 
                            condition = And [
                                            Planet
                                            OwnedBy empire = Source.Owner
                                        ]
the key portion of the debugging output is

Code: Select all

double ref parser trying int stats
 double ref parser trying int complex var
found JumpsBetween
Constructing VariableRef property name: Source.SystemID)
===============
Constructing VariableRef property name: Source.SystemID)
===============
 JumpsBetween got first object ID ref 
trying Statistic2 type(7)
trying Statistic3 type(7)
Constructing VariableRef property name: LocalCandidate.SystemID)
===============

Constructing And Condition1: [ that is a Planet and that belongs to source's owner empire]
======================
 Statistic3 finishing after const, free or bound.
-----
Constructing Max Statistic on valueref-- statistic: [(stat type: 7)type(int) (MAX)(value ref: local condition candidate's system id)(property name: )(sampling condition:  that is a Planet and that belongs to source's owner empire)]
=================
 JumpsBetween got second object ID ref 
---------
Constructing ComplexVariable: Complex Variable: [(Variable Name: JumpsBetween) ((ir1: source's system id), (ir2: statistic: [(stat type: 7)type(int) (MAX)(value ref: local condition candidate's system id)(property name: )(sampling condition:  that is a Planet and that belongs to source's owner empire)])]==================
 double ref parser finishing int complex var
Constructing StaticCast from(int)  to (double) of [Complex Variable: [(Variable Name: JumpsBetween) ((ir1: source's system id), (ir2: statistic: [(stat type: 7)type(int) (MAX)(value ref: local condition candidate's system id)(property name: )(sampling condition:  that is a Planet and that belongs to source's owner empire)])]]
======
There is some doubling up (or more) of ValueRef & Condition constructions due to deep copies being made by the parser (even more than is shown, I redacted some), but at least it parses ok.

for the problem child statistic, though,

Code: Select all

// The following currently causes a crash upon parsing
Statistic name = "STATISTICS_TEST_3" value =
    MAX Value = JumpsBetween object = source.SystemID object = LocalCandidate.SystemID 
                            condition = And [
                                            OwnedBy empire = Source.Owner
                                            Planet
                                        ]
the debug output for this whole statistic is just

Code: Select all

 double ref parser trying int stats
trying Statistic2 type(7)
trying Statistic3 type(7)
 Statistic3 trying complex var.
The thing that is particularly perplexing here is that at this point, where the complex variable parser causes a segfault, it has already been used successfully many times. It appears to me that somehow when stat3 is initialized it is not getting a proper reference to the complex variable parser, but instead is working with a reference to some temporary copy which later has gone out of scope. I've tried doing everything I can to avoid that, but haven't been able to figure it out.

I did notice that the complex variable parser is handles a bit differently than the other parsers (i.e., not kept as a function local static), and tried restructuring along those lines, but to no avail. That attempt is attached is a "restructured" patch; it seems partially successful in that it apparently avoids the crash, but unless I stick with having the stats and complex_variable parsers use only the most simplistic int refs (which is too restrictive for either of the above examples), then I get initialization deadlock like we used to have.

So, at least this should be some helpful info for other future parser debugging needs, but I think I need to take a long break from any more attempts on this stat3 of a complex variable.
Attachments

[The extension patch has been deactivated and can no longer be displayed.]

[The extension patch has been deactivated and can no longer be displayed.]

If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13603
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: parsing experiment notes

#19 Post by Geoff the Medio »

Does the attached patch work on Linux / OSX?

It removes the "property =" variant of Statistic, leaving just the "value = (ValueRef)" variant (and the valueless Count and If statistic types), makes the int and double forms of Statistic parsing consistent, consolidates the parameters to the Statistic parser so it just takes one rule which is defined at the calling level to accept various options for the value property of the Statistic (instead of passing many possible value rules), switches to using >> instead of > to create the bound variable parser to avoid potential ambiguous cases parse failures with the double rule accepting an int expression...

The complex variable rules are commented out when constructing the Statistic value rule, as presumably these would cause parser crashes.
Attachments

[The extension patch has been deactivated and can no longer be displayed.]


User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: parsing experiment notes

#20 Post by Dilvish »

Geoff the Medio wrote:Does the attached patch work on Linux / OSX?
Applied against r7910 because SourceForge is currently unresponsive, this compiles fine, doesn't trigger any parser errors and appears to run fine over a few turns test.

I saw on Github that the complex parser had been moved over to using a simple int, and that's of course what necessitated Vezzra to comment out the test empire statistics. I agree with you that all the empire_id parts of the complex parsers are totally suitable as simple ints. JumpsBetween is the one int complex variable ValueRef there where it would be very very nice to be able to have a more involved int_value_ref, for its object references. That part was working fine, and when I experimented with trying to clear up the statistic_3 troubles by having the complex_variable_parser work only with simple ints, as you have it now, it did not improve the situation, at least not in my attempts

Still we can experiment more for a while with the complex var parser only using simple ints, and seeing if somehow that could clear up the troubles with the statistics_3 parsing. If so, then we could move on to trying to get a couple cases working with the more involved int_ref. Besides the int complex var JumpsBetween, the similar <double> complex var ref DirectDistance is another that we'd really want to be able to take a more involved valueref for its object references. Perhaps we should just handle those two separately from the others.

Another thing I might try is regarding where all the rules are held. The general advice for dealing with rule scope problems seems to be to keep the rule instances all 'owned' in the same location. That might just create more initialization deadlocks for us, but it could be that the compiler/linker could deal with that better if all the instantiations were together in the same compilation unit. In order to do that a fair bit of file restructuring would probably be necessary, breaking off header files from many of the current parser.cpp files.
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Vezzra
Release Manager, Design
Posts: 6102
Joined: Wed Nov 16, 2011 12:56 pm
Location: Sol III

Re: parsing experiment notes

#21 Post by Vezzra »

Geoff the Medio wrote:Does the attached patch work on Linux / OSX?
It builds and runs fine, at least to the point where I can start a game and everything looks ok as far as I could see on a first quick glance. I do get parser errors when I uncomment the test empire statistics, but that issue already existed without the patch and, judging by Dilvish' comment, was to be expected.

One interesting thing: when I commented out the first two test empire statistics (that used to work before) and uncomment the third (which caused crashes before), I don't get a crash now, but this parse error:

Code: Select all

2015-02-10 19:54:52,795 ERROR Server : /Users/user/SoftwareProjekte/FO/current/FreeOrion/Xcode/build/Test/FreeOrion.app/Contents/Resources/default/empire_statistics.txt:97:35: Parse error.  Expected unnamed-rule here:
                                        ]

*/
// The following currently causes a crash upon parsing
Statistic name = "STATISTICS_TEST_3" value =
    1.0 + MAX Value = JumpsBetween object = source.SystemID object = LocalCandidate.SystemID 
                                   ^
                            condition = And [
                                            Planet
                                            OwnedBy empire = Source.Owner
                                        ]
What surprised me was the error message and the point where the parsing failed. I expected the same as with the first test empire statistic:

Code: Select all

2015-02-10 20:11:00,386 ERROR Server : /Users/user/SoftwareProjekte/FO/current/FreeOrion/Xcode/build/Test/FreeOrion.app/Contents/Resources/default/empire_statistics.txt:81:61: Parse error.  Expected simple integer expression (constant, free or bound variable) here:
// Tests 1 and 2 currently work, test 3 does not.



Statistic name = "STATISTICS_TEST_1" value =
    1.0 + JumpsBetween object = source.SystemID object = MAX Value = LocalCandidate.SystemID
                                                             ^
                            condition = And [
                                            Planet
                                            OwnedBy empire = Source.Owner
                                        ]
But that's probably because the parser doesn't get to the point where it could determine if the value returned by JumpDistance matches. Anyway, I thought I mention it, just in case.

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13603
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: parsing experiment notes

#22 Post by Geoff the Medio »

Dilvish wrote:Another thing I might try is regarding where all the rules are held. The general advice for dealing with rule scope problems seems to be to keep the rule instances all 'owned' in the same location.
I've been pondering if such a change is necessary, but have been reluctant to try due to the amount of restructuring involved.

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13603
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: parsing experiment notes

#23 Post by Geoff the Medio »

Vezzra wrote:What surprised me was the error message and the point where the parsing failed.
That is strange. I get the same result. I think it should reject JumpsBetween as a ValueRef if int_complex_variable_cast is commented out in statistic_sub_value_ref in double_parser_rules().

If I uncomment the complex variable parsers in that statistic_sub_value_ref then it does parse and appears to work in game, though that's just on Windows, probably...

User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: parsing experiment notes

#24 Post by Dilvish »

Geoff the Medio wrote:If I uncomment the complex variable parsers in that statistic_sub_value_ref then it does parse and appears to work in game, though that's just on Windows, probably...
That seems to work fine for me also, and that is *huge*-- that's the key thing I've been trying so hard to get working.

The "unnamed rule" failure is on the face of it odd, but some of the mystery goes away if you add a name to statistic_sub_value_ref in DoubleValueRef.cpp -- that is the rule that is failing. Like you, it seems to me that the error should point to the beginning of "JumpsBetween". Also, adding some extra logging into the JumpsBetween parser indicates that no attempt is being made to apply it there.

I should catch up on reviewing Cjkjvfnby's AI work before I look at this more, but it does seem you got a critical new piece working.
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13603
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: parsing experiment notes

#25 Post by Geoff the Medio »

Dilvish wrote:
Geoff the Medio wrote:If I uncomment the complex variable parsers in that statistic_sub_value_ref then it does parse and appears to work in game, though that's just on Windows, probably...
That seems to work fine for me also, and that is *huge*-- that's the key thing I've been trying so hard to get working.
I did not expect these changes to have that result... but OK... good, I guess?

User avatar
Dilvish
AI Lead and Programmer Emeritus
Posts: 4768
Joined: Sat Sep 22, 2012 6:25 pm

Re: parsing experiment notes

#26 Post by Dilvish »

Geoff the Medio wrote:I did not expect these changes to have that result... but OK... good, I guess?
Great, in fact. Please go ahead and commit that patch, with the the complex variable parsers uncommented in the statistic_sub_value_ref's.

As a further indication of the progress made, if I also add int_var_statistic() to the JumpsBetween rule like so:

Code: Select all

            jumps_between
                =   (
                            tok.JumpsBetween_ [ _a = construct<std::string>(_1) ]
                        >   parse::label(Object_token) >    (int_value_ref [_b=_1] | int_var_statistic() [_b=_1])
                        >   parse::label(Object_token) >    (int_value_ref [_c=_1] | int_var_statistic() [_c=_1])
                    ) [ _val = new_<ValueRef::ComplexVariable<int> >(_a, _b, _c, _f, _d, _e) ]
                ;
then all three of the experimental empire statistics will work fine for me. Note that because int_value_ref and int_var_statistic() have different attribute types it is necessary that they each get their own semantic action rather than using something like

Code: Select all

(int_value_ref | int_var_statistic()) [_b=_1]
Now, this may or may not be how we really want to wind up handling JumpsBetween (and DirectDistance), but I tend to think you may as well put this in also until such time as we figure out something better.

One thing-- would there be any harm in leaving in the ValueRef.h code for the other constructors for ValueRef::Statistic? Even if we need to leave out that portion of the parser for now, I'd like to look at adding it back and it seems no harm in leaving in the underlying constructors. Or did that make some problem with the compiler doing some overeager implicit casting?
If I provided any code, scripts or other content here, it's released under GPL 2.0 and CC-BY-SA 3.0

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13603
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: parsing experiment notes

#27 Post by Geoff the Medio »

Dilvish wrote:would there be any harm in leaving in the ValueRef.h code for the other constructors for ValueRef::Statistic? Even if we need to leave out that portion of the parser for now, I'd like to look at adding it back and it seems no harm in leaving in the underlying constructors. Or did that make some problem with the compiler doing some overeager implicit casting?
No problems with casting, but why do you want to add back the (I assume) property = variant of statistics? I removed it because it was redundant with the value = variant, and figured having a simpler interface / format for statistics was better...

User avatar
Vezzra
Release Manager, Design
Posts: 6102
Joined: Wed Nov 16, 2011 12:56 pm
Location: Sol III

Re: parsing experiment notes

#28 Post by Vezzra »

Geoff the Medio wrote:I did not expect these changes to have that result... but OK... good, I guess?
Oh yes!!! :D That fixed things on OSX as well - perfect. With the changes already committed the third test empire statistic doesn't crash nor throw a parse error anymore. The first two however still complain about expecting the simple int expression.

When applying Dilvish' fix:
Dilvish wrote:As a further indication of the progress made, if I also add int_var_statistic() to the JumpsBetween rule like so:

Code: Select all

            jumps_between
                =   (
                            tok.JumpsBetween_ [ _a = construct<std::string>(_1) ]
                        >   parse::label(Object_token) >    (int_value_ref [_b=_1] | int_var_statistic() [_b=_1])
                        >   parse::label(Object_token) >    (int_value_ref [_c=_1] | int_var_statistic() [_c=_1])
                    ) [ _val = new_<ValueRef::ComplexVariable<int> >(_a, _b, _c, _f, _d, _e) ]
                ;
then all three of the experimental empire statistics will work fine for me.
then all three work on OSX too.

That's one major breakthrough :D

Even if it's maybe not the perfect solution, can we commit Dilvish' fix? I'll try to merge these changes to the rev col branch as soon as I can get to it, and want to try out if the build-time-dependence-on-nearest-colony-with-desired-species thing for colony buildings is going to work now. That was the one thing why I didn't attempt to merge back into trunk yet.

User avatar
Vezzra
Release Manager, Design
Posts: 6102
Joined: Wed Nov 16, 2011 12:56 pm
Location: Sol III

Re: parsing experiment notes

#29 Post by Vezzra »

Vezzra wrote:I'll try to merge these changes to the rev col branch as soon as I can get to it, and want to try out if the build-time-dependence-on-nearest-colony-with-desired-species thing for colony buildings is going to work now.
Ok, took a quick shot at it, and it turns out we still have issues. When I implement the formula Dilvish suggested:

Code: Select all

    buildtime = max(5,
        min value = JumpsBetween object = Target.SystemID object = LocalCandidate.SystemID
            condition = And [
                Planet
                OwnedBy empire = Source.Owner
                Species name = "SP_ABADDONI"
                Population low = 3
                Happiness low = 5
                ResourceSupplyConnected empire = Source.Owner condition = Target
            ]
    )
for the buildtime of the colony buildings, I get the following parse error:

Code: Select all

2015-02-11 13:24:26,029 ERROR Server : /Users/user/SoftwareProjekte/FO/colonization/FreeOrion/Xcode/build/Test/FreeOrion.app/Contents/Resources/default/buildings.txt:1786:33: Parse error.  Expected simple integer expression (constant, free or bound variable) here:
BuildingType
    name = "BLD_COL_ABADDONI"
    description = "BLD_COL_ABADDONI_DESC"
    buildcost = 50 * (1 + 0.06 * SpeciesColoniesOwned empire = Source.Owner)
    buildtime = max(5,
        min value = JumpsBetween object = Target.SystemID object = LocalCandidate.SystemID
                                 ^
            condition = And [
                Planet
                OwnedBy empire = Source.Owner
                Species name = "SP_ABADDONI"
                Population low = 3
All the test empire statistics parse fine however... so I'm a bit confused: what's the difference here? I mean, test statistic#3 looks like this:

Code: Select all

Statistic name = "STATISTICS_TEST_3" value =
    1.0 + MAX value =
        JumpsBetween
            object = Source.SystemID
            object = LocalCandidate.SystemID
            condition = And [
                Planet
                OwnedBy empire = Source.Owner
            ]
and that works. Huh?

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13603
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: parsing experiment notes

#30 Post by Geoff the Medio »

Vezzra wrote:...and that works. Huh?
Try putting

Code: Select all

    1 + MAX value =
        JumpsBetween
            object = Source.SystemID
            object = Target.SystemID
            condition = And [
                Planet
                OwnedBy empire = Source.Owner
            ]
as the buildtime for the building?

And then try

Code: Select all

    max(5, MIN value =
        JumpsBetween
            object = Source.SystemID
            object = Target.SystemID
            condition = And [
                Planet
                OwnedBy empire = Source.Owner
            ]
    )

Post Reply