Example #1
0
        private void ValidateDataField(BcDataEntry data, int level, string name, string patt)
        {
            var field = data as BcDataField;

            Assert.IsNotNull(field);
            Assert.AreEqual(level, field.Level);
            Assert.AreEqual(name, field.Name);
            Assert.AreEqual(patt, field.Pattern);
        }
Example #2
0
        internal static BcProgram Parse(List <LineOfCode> lines)
        {
            BcProgram prg = new BcProgram();

            if (lines == null || lines.Count == 0)
            {
                return(prg);
            }
            int index = 0;

            // IDENTIFICATION DIVISION
            if (IsZoneAExact(lines[index], IDENTIFICATION_DIVISION))
            {
                // parse the entire division as key-value pairs
                index++;
                int    dot1, dot2;
                string key, val;
                while (index < lines.Count && IsZoneB(lines[index]))
                {
                    dot1 = lines[index].Content.IndexOf('.');
                    dot2 = lines[index].Content.LastIndexOf('.');
                    if (dot1 < 0 || (dot1 != dot2 && dot2 != lines[index].Content.Length - 1))
                    {
                        Logger.ErrorIdDivClauseBug(lines[index].Line, lines[index].Content);
                    }
                    key = lines[index].Content.Substring(0, dot1).Trim();
                    if (dot1 == dot2)
                    {
                        val = String.Empty;
                    }
                    else
                    {
                        val = lines[index].Content.Substring(dot1 + 1, dot2 - dot1 - 1).Trim();
                    }
                    if (prg.Identifications.ContainsKey(key))
                    {
                        Logger.ErrorIdDivClauseDup(lines[index].Line, lines[index].Content);
                    }
                    prg.Identifications[key] = val;
                    index++;
                }
            }
            // DATA DIVISION
            Dictionary <string, BcDataEntry> CachedData = new Dictionary <string, BcDataEntry>();
            HashSet <string> Duplicates = new HashSet <string>();

            if (index < lines.Count && IsZoneAExact(lines[index], DATA_DIVISION))
            {
                index++;
                // there is a data division
                while (index < lines.Count && !IsZoneAExact(lines[index], PROCEDURE_DIVISION))
                {
                    string val = lines[index].Content.Replace(" ", "");
                    if (val[val.Length - 1] == '.')
                    {
                        val = val.Substring(0, val.Length - 1);
                    }
                    uint lineNo = lines[index].Line;
                    int  level  = GetIntOrComplain(lineNo, val.Substring(0, 2), Logger.ErrorDataDivWrongLevel);
                    int  occurs = 1;
                    // OCCURS
                    int occursPos = val.IndexOf(OCCURS);
                    if (occursPos >= 0)
                    {
                        occurs = GetIntOrComplain(lineNo, val.Substring(occursPos + OCCURS.Length), Logger.ErrorDataDivWrongOccurs);
                        val    = val.Substring(0, occursPos);
                    }
                    // PICTURE
                    int picPos = val.LastIndexOf(PICTURE); // using last index to avoid problems where PICTURE is a (part of) the name
                    if (picPos >= 0)
                    {
                        string      pat = val.Substring(picPos + PICTURE.Length);
                        BcDataEntry f   = new BcDataField(level, val.Substring(2, picPos - 2), pat);
                        RememberFieldType(f, CachedData, Duplicates);
                        ConnectField(prg.Data, f, lineNo, level, occurs);
                        index++;
                        continue;
                    }
                    // LIKE
                    int lastLikePos = val.LastIndexOf(LIKE);
                    if (lastLikePos >= 0)
                    {
                        bool   done = false;
                        int    curLikePos = -LIKE.Length;
                        string s1, s2;
                        while (!done && curLikePos < lastLikePos)
                        {
                            curLikePos = val.IndexOf(LIKE, curLikePos + LIKE.Length);
                            s1         = val.Substring(2, curLikePos - 2);
                            s2         = val.Substring(curLikePos + LIKE.Length);
                            if (CachedData.ContainsKey(s2))
                            {
                                BcDataEntry f = CachedData[s2].Like();
                                f.Level = level;
                                f.Name  = s1;
                                RememberFieldType(f, CachedData, Duplicates);
                                ConnectField(prg.Data, f, lineNo, level, occurs);
                                done = true;
                            }
                        }
                        if (done)
                        {
                            index++;
                            continue;
                        }
                    }
                    // nothing
                    var v = new BcDataView(level, val.Substring(2));
                    RememberFieldType(v, CachedData, Duplicates);
                    ConnectField(prg.Data, v, lineNo, level, occurs);
                    index++;
                }
            }

            // PROCEDURE DIVISION
            if (index < lines.Count && IsZoneAExact(lines[index], PROCEDURE_DIVISION))
            {
                index++;
                var currParaName = "";
                var currParaCode = new BcBlock();
                var currSentence = new BcSentence();
                // there is a procedure division
                while (index < lines.Count)
                {
                    var tokens = Tokenise(lines[index]);
                    for (int i = 0; i < tokens.Count; i++)
                    {
                        if (tokens[i] is EOPToken tokenP)
                        {
                            if (currSentence.Statements.Count > 0)
                            {
                                currParaCode.Sentences.Add(currSentence);
                                currSentence = new BcSentence();
                            }
                            if (currParaCode.Sentences.Count > 0)
                            {
                                prg.Paragraphs.Add(currParaName, currParaCode);
                                currParaCode = new BcBlock();
                                if (i + 2 < tokens.Count && tokens[i + 1] is UnquotedToken tokenPU && tokens[i + 2] is EOSToken)
                                {
                                    currParaName = tokenPU.Value;
                                    i           += 2;
                                }
                                else
                                {
                                    currParaName = "";
                                }
                            }
                        }
                        else if (tokens[i] is EOSToken tokenS)
                        {
                            if (currSentence.Statements.Count > 0)
                            {
                                currParaCode.Sentences.Add(currSentence);
                                currSentence = new BcSentence();
                            }
                        }
                        else if (tokens[i] is QuotedToken tokenQ)
                        {
                            Logger.ErrorStrayQuoted(tokenQ);
                        }
                        else if (tokens[i] is UnquotedToken tokenU)
                        {
                            if (tokenU.Value.StartsWith(ACCEPT))
                            {
                                // TODO cover all possible arguments, now it accepts only one trivial identifier
                                var acc  = new BcAccept();
                                var name = tokenU.Value.Substring(ACCEPT.Length);
                                acc.Accepted.Add(new BcIdRef(name));
                                currSentence.Statements.Add(acc);
                            }
                            else
                            {
                                Logger.ErrorNotImplementedYet(tokenU.Row, tokenU.Col, tokenU.Value);
                            }
                        }
                        else
                        {
                            Logger.ErrorUnrecognisedToken(tokens[i]);
                        }
                    }