Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with Antlr4 Java 7 Grammar expression Parser rule #1323

Closed
sufail opened this issue Nov 5, 2016 · 4 comments
Closed

Issue with Antlr4 Java 7 Grammar expression Parser rule #1323

sufail opened this issue Nov 5, 2016 · 4 comments

Comments

@sufail
Copy link

sufail commented Nov 5, 2016

I found this issue for the following input

public String publishAbsencesApprovalsEvent(Map<String,Object> absenceValues) {

// inside this method there is a pretty much long string which spans around 150 lines.

}

When I try to create a ParseTree for this input file, it's got hanged like forever. I guess there is a decision-making issue for the grammar for the below two rules.

typeArguments
: '<' typeArgument (',' typeArgument)* '>'
;

expression
: //many alternatives
| expression ('<=' | '>=' | '>' | '<') expression #logical

When I commented out the #logical alternative and re-ran it's worked.

I guess there is a token matching decision from lexer to Parser level which makes it hang forever.
Please let me know if there is a solution for this without altering much of the grammar file.

@parrt
Copy link
Member

parrt commented Nov 19, 2016

Is this java or java8 grammar? it is hitting a nonlinearity. not a bug but not fun either. ;)

@parrt parrt closed this as completed Nov 19, 2016
@sufail
Copy link
Author

sufail commented Nov 20, 2016

@parrt Well it still seems a for me.
I am using Java7 grammar. https://github.com/antlr/grammars-v4/blob/master/java/Java.g4
Please have a look at the following input file snippet

public class AbsencesApprovalsEventsAMImpl extends ApplicationModuleImpl {

    public Object publishAbsencesApprovalsEvent(Map<String,Integer>  absenceValues) {

    if (!(transactionId.equals(null)) && !(requestor.equals(null))) {


        String payload = "<AbsencesApprovalsRequest xmlns=\"http://xmlns.oracle.com/apps/hcm/globalAbsences/approvals/model/entity/events/schema/AbsencesApprovalsEvent\">"
                + "<TransactionId>"
                + transactionId
                + "</TransactionId>"
                + "<Requestor>"
                + requestor
                + "</Requestor>"
                + "<PersonName>"
                + org.apache.commons.lang.StringEscapeUtils
                        .escapeXml(personName)
                + "</PersonName>"
                + "<AbsenceType>"
                + org.apache.commons.lang.StringEscapeUtils
                        .escapeXml(absenceType)
                + "</AbsenceType>"
                + "<AbsenceStartDate>"
                + absenceStartDate
                + "</AbsenceStartDate>"
                + "<AbsenceEndDate>"
                + absenceEndDate
                + "</AbsenceEndDate>"
                + "<AbsenceStatusCd>"
                + AbsenceStatusCd
                + "</AbsenceStatusCd>"
                + "<SubmittedDate>"
                + SubmittedDate
                + "</SubmittedDate>"
                + "<StartDate>"
                + StartDate
                + "</StartDate>"
                + "<DiseaseCode>"+

                (String) absenceValues.get("DiseaseCode")
                + "</DiseaseCode>"
                + "<LegalEntity>"
                + org.apache.commons.lang.StringEscapeUtils
                        .escapeXml((String) absenceValues
                                .get("LegalEntity"))
                + "</LegalEntity>"
                + "<LegislativeDataGroup>"
                + org.apache.commons.lang.StringEscapeUtils
                        .escapeXml((String) absenceValues
                                .get("LegislativeDataGroup"))
                + "</LegislativeDataGroup>"
                + "<AbsenceTypeReasons>"
                + org.apache.commons.lang.StringEscapeUtils
                        .escapeXml((String) absenceValues
                                .get("AbsenceTypeReasons"))
                + "</AbsenceTypeReasons>"
                + "<AbsencePatternCd>"
                + (String) absenceValues.get("AbsencePatternCd")
                + "</AbsencePatternCd>"
                + "<AbsenceStatusCd>"
                + (String) absenceValues.get("AbsenceStatusCd")
                + "</AbsenceStatusCd>"
                + "<ChildEventTypeCd>"
                + (String) absenceValues.get("ChildEventTypeCd")
                + "</ChildEventTypeCd>"
                + "<ConfirmedDate>"
                +

                (Date) absenceValues.get("ConfirmedDate")
                + "</ConfirmedDate>"
                + "<Duration>"
                + (BigDecimal) absenceValues.get("Duration")
                + "</Duration>"
                + "<StartTime>"
                +

                (Timestamp) absenceValues.get("StartTime")
                + "</StartTime>"
                + "<EndTime>"
                + (Timestamp) absenceValues.get("EndTime")
                + "</EndTime>"
                + "<OpenEndedFlag>"
                + (String) absenceValues.get("OpenEndedFlag")
                + "</OpenEndedFlag>"
                + "<PlannedEndDate>"
                + (Date) absenceValues.get("PlannedEndDate")
                +

                "</PlannedEndDate>"
                + "<Uom>"
                + (String) absenceValues.get("Uom")
                + "</Uom>"
                + "<SingleDayFlag>"

                +

                (String) absenceValues.get("SingleDayFlag")
                + "</SingleDayFlag>"
                + "<StartDateDuration>"
                + (BigDecimal) absenceValues.get("StartDateDuration")
                + "</StartDateDuration>"
                + "<EndDateDuration>"
                + (BigDecimal) absenceValues.get("EndDateDuration")
                + "</EndDateDuration>"
                + "<Comments>"
                +

                org.apache.commons.lang.StringEscapeUtils
                        .escapeXml((String) absenceValues.get("Comments"))
                + "</Comments>"
                + "<CreatedBy>"
                + (String) absenceValues.get("CreatedBy")
                + "</CreatedBy>"
                + "<CreationDate>"
                + (Timestamp) absenceValues.get("CreationDate")
                + "</CreationDate>"
                + "<LastUpdateDate>"
                + (Timestamp) absenceValues.get("LastUpdateDate")
                + "</LastUpdateDate>"
                + "<LastUpdateLogin>"
                + (String) absenceValues.get("LastUpdateLogin")
                + "</LastUpdateLogin>"
                + "<LastUpdatedBy>"
                + (String) absenceValues.get("LastUpdatedBy")
                + "</LastUpdatedBy>"
                + "<SubmittedDate>"
                + (Date) absenceValues.get("SubmittedDate")
                + "</SubmittedDate>"
                + "<AbsenceEntryBasicFlag>"
                +

                (String) absenceValues.get("AbsenceEntryBasicFlag")
                + "</AbsenceEntryBasicFlag>"
                + "<IllnessStartDate>"
                + (Date) absenceValues.get("IllnessStartDate")
                + "</IllnessStartDate>"
                + "<StartDatetime>"
                + (Timestamp) absenceValues.get("StartDatetime")
                + "</StartDatetime>"
                + "<EndDatetime>"
                + (Timestamp) absenceValues.get("EndDatetime")
                + "</EndDatetime>"
                + "<AbsenceDispStatusCd>"
                + (String) absenceValues.get("AbsenceDispStatusCd")
                + "</AbsenceDispStatusCd>"
                + "<Durationuomname>"
                + (String) absenceValues.get("Durationuomname")
                + "</Durationuomname>"
                + "<Statuslookupname>"
                + (String) absenceValues.get("Statuslookupname")
                + "</Statuslookupname>"
                + "<Typename>"
                + org.apache.commons.lang.StringEscapeUtils
                        .escapeXml((String) absenceValues.get("Typename"))
                + "</Typename>"
                + "<Employername>"
                + org.apache.commons.lang.StringEscapeUtils
                        .escapeXml((String) absenceValues
                                .get("Employername"))
                + "</Employername>"
                + "<PartialDay>"
                + (String) absenceValues.get("PartialDay")
                + "</PartialDay>"
                + "<MapEventTypeCd>"
                + (String) absenceValues.get("MapEventTypeCd")
                + "</MapEventTypeCd>"
                + "<EmpLockIfConfirmCd>"
                + (String) absenceValues.get("EmpLockIfConfirmCd")
                + "</EmpLockIfConfirmCd>"
                + "<EmpAllowUpdatesCd>"
                + (String) absenceValues.get("EmpAllowUpdatesCd")
                + "</EmpAllowUpdatesCd>"
                + "<MinDuration>"
                + (BigDecimal) absenceValues.get("MinDuration")
                + "</MinDuration>"
                + "<MaxDuration>"
                + (BigDecimal) absenceValues.get("MaxDuration")
                + "</MaxDuration>"
                + "<MinDurationRuleCd>"
                + (String) absenceValues.get("MinDurationRuleCd")
                + "</MinDurationRuleCd>"
                + "<MaxDurationRuleCd>"
                + (String) absenceValues.get("MaxDurationRuleCd")
                + "</MaxDurationRuleCd>"
                + "<MaxDurationRuleCd>"
                + (String) absenceValues.get("MaxDurationRuleCd")
                + "</MaxDurationRuleCd>"
                + "<AllowDeleteDate>"
                + (Date) absenceValues.get("AllowDeleteDate")
                + "</AllowDeleteDate>"
                + "<MgrLockIfConfirmCd>"
                + (String) absenceValues.get("MgrLockIfConfirmCd")
                + "</MgrLockIfConfirmCd>"
                + "<MgrAllowUpdatesCd>"
                + (String) absenceValues.get("MgrAllowUpdatesCd")
                + "</MgrAllowUpdatesCd>"
                + "<NotificationDate>"
                + (Date) absenceValues.get("NotificationDate")
                + "</NotificationDate>"
                + "<SplCondition>"
                + (String) absenceValues.get("SplCondition")
                + "</SplCondition>"
                + "<LateNotifyFlag>"
                +

                (String) absenceValues.get("LateNotifyFlag")
                + "</LateNotifyFlag>"
                + "<InitialTimelyNotifyFlag>"
                + (String) absenceValues.get("InitialTimelyNotifyFlag")
                + "</InitialTimelyNotifyFlag>"
                + "<TimelinessOverrideDate>"
                + (Date) absenceValues.get("TimelinessOverrideDate")
                + "</TimelinessOverrideDate>"
                + "<CertificationAuthFlag>"
                + (String) absenceValues.get("CertificationAuthFlag")
                + "</CertificationAuthFlag>"
                + "<AuthStatusUpdateDate>"
                + (Date) absenceValues.get("AuthStatusUpdateDate")
                + "</AuthStatusUpdateDate>"
                + "<PeriodOfIncapToWorkFlag>"
                + (String) absenceValues.get("PeriodOfIncapToWorkFlag")
                + "</PeriodOfIncapToWorkFlag>"
                + "<EstablishmentDate>"
                + (Date) absenceValues.get("EstablishmentDate")
                + "</EstablishmentDate>"
                + "<UserMode>"
                + (String) absenceValues.get("UserMode")
                + "</UserMode>"
                + "<LegislationCode>"
                + (String) absenceValues.get("LegislationCode")
                + "</LegislationCode>"
                + "<Name>"
                + (String) absenceValues.get("Name")
                + "</Name>"
                + "<AbsenceDispStatus>"
                +

                org.apache.commons.lang.StringEscapeUtils
                        .escapeXml((String) absenceValues
                                .get("AbsenceDispStatus"))
                + "</AbsenceDispStatus>"
                + "<AbsenceDispDate>"
                + (String) absenceValues.get("AbsenceDispDate")
                + "</AbsenceDispDate>"
                + "<TimeFormat>"
                + (String) absenceValues.get("TimeFormat")
                + "</TimeFormat>"
                + "<IntendToWork>"
                + (String) absenceValues.get("IntendToWork")
                + "</IntendToWork>"
                + "<StartDtPartialDay>"
                + (String) absenceValues.get("StartDtPartialDay")
                + "</StartDtPartialDay>"
                + "<EndDtPartialDay>"
                + (String) absenceValues.get("EndDtPartialDay")
                + "</EndDtPartialDay>"
                + "<DispTypeName>"
                + (String) absenceValues.get("DispTypeName")
                + "</DispTypeName>"
                + "<AllowUpdateFlag>"
                + (String) absenceValues.get("AllowUpdateFlag")
                + "</AllowUpdateFlag>"
                + "<BindpEmpAllowUpdatesCd>"
                + (String) absenceValues.get("BindpEmpAllowUpdatesCd")
                + "</BindpEmpAllowUpdatesCd>"
                + "<BindpMgrAllowUpdatesCd>"
                + (String) absenceValues.get("BindpMgrAllowUpdatesCd")
                + "</BindpMgrAllowUpdatesCd>"
                + "<BlockedLeaveCandidate>"
                + (String) absenceValues.get("BlockedLeaveCandidate")
                + "</BlockedLeaveCandidate>"
                + "<EmpUserId>"
                + org.apache.commons.lang.StringEscapeUtils
                        .escapeXml((String) absenceValues.get("EmpUserId"))
                + "</EmpUserId>"
                + "<PersonId>"
                + personId
                + "</PersonId>"
                + "<AssignmentId>"
                + assignmentId
                + "</AssignmentId>"
                + "<NotificationName>"
                + rowStatus
                + "</NotificationName>"
                + "<ApprovalType>"
                + " "
                + "</ApprovalType>"
                + "</AbsencesApprovalsRequest>";

        String eventNameSpace = "http://xmlns.oracle.com/apps/hcm/globalAbsences/approvals/model/entity/events/edl/AbsencesApprovalsEvent";
        String eventName = "AbsencesApprovalsEvent";

        try {

        } catch (Exception e) {
            if (conn != null) {
                conn.close();
            }
            throw new JboException(e);
        }

        retStatus = "SUCCESS";

    }
    return retStatus;
}

}
`
If you parse the above file using the grammar for java7, it will halt , like forever.

Now if I change something in the input file like what follows.

case 1:
public Object publishAbsencesApprovalsEvent(Map<String,Integer> absenceValues) {

Removing the Generic Symbols from the method argument. That is changing

Map<String,Integer> absenceValues to Map abscenceValues ( or like anything without "<" and ">" symbols)

Keeping the rest of the code as they are.

case 2:

Keeping the method argument as it is and reducing the length of the String payload ( the payload string spans across multiple lines from line number 11 to line number 291)
I reduced the string to span across from line 11 to line say, 41.
Keeping the rest of the code as they are.

In both cases, it Works.

When I tried with Java8 grammar (https://github.com/antlr/grammars-v4/blob/master/java8/Java8.g4), it worked.

For some reasons, I can't change my underlying grammar. I need to get this done using Java7 grammar itself. I tried almost everything, from using to unbuffered streams to setting SSL prediction but nothing worked for me.
I have a strong feeling that this is because Antlr failed to make a prediction for these tokens "<" ">" as these tokens appear in two ambiguous rules.

typeParameters
: '<' typeParameter (',' typeParameter)* '>'
;

expression
: // many alternatives
| expression ('<=' | '>=' | '>' | '<') expression #logical

I changed the expression rule to something like this

expression
: //many alternatives
| logicalExpression #logical

and

logicalExpression
: logicalOperands ('<=' | '>=' | '>' | '<') logicalOperands
;
logicalOperands
: logicalOperand ('+' logicalOperand)* ;

logicalOperand
: Identifier
| Identifier '(' ')'
| Identifier '(' expression ')'
;

For my next run, it worked.

I have written some APIs targeting Java7.g4 grammar and can't move straight away to Java8.g4 as the rule name among them are entirely different.

@parrt
Copy link
Member

parrt commented Nov 21, 2016

Yes, ANTLR's ALL(*) is O(n^4) worst case and you hit it with that. The java8 grammar doesn't use left-recursive expr and so performs better in this case.

@parrt
Copy link
Member

parrt commented Nov 22, 2016

Dup of #994

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants