Ejemplo n.º 1
0
func makeSynthRules(l lexer.Lexer, synthSymbols map[string]bool, userFn UserFn) ([]Rule, error) {
	var rules []Rule
	if userFn == nil {
		userFn = DefaultUserFn
	}
	for tok := range synthSymbols {
		if !isSynthName(tok) {
			tlog.Panic("should be a synth name but it's not: ", tok)
		}
		lsid, err := l.GetSymbolSet().GetByName(tok)
		if err != nil {
			return rules, err
		}
		end := tok[len(tok)-1:]
		tok := tok[:len(tok)-1]
		rsid, err := rhsCase(l, tok)
		if err != nil {
			return rules, err
		}
		switch end {
		case "?":
			rules = append(rules, Rule{lsid, []syms.SymbolID{syms.EMPTY}, userFn})
			rules = append(rules, Rule{lsid, []syms.SymbolID{rsid}, userFn})
		case "*":
			rules = append(rules, Rule{lsid, []syms.SymbolID{syms.EMPTY}, userFn})
			rules = append(rules, Rule{lsid, []syms.SymbolID{lsid, rsid}, userFn})
		case "+":
			rules = append(rules, Rule{lsid, []syms.SymbolID{rsid}, userFn})
			rules = append(rules, Rule{lsid, []syms.SymbolID{lsid, rsid}, userFn})
		}
	}

	return rules, nil
}
Ejemplo n.º 2
0
func lhsCase(l lexer.Lexer, lhs string) (syms.SymbolID, error) {
	symbols := l.GetSymbolSet()
	sid, err := symbols.GetByName(lhs)
	if err == nil {
		return sid, nil
	}
	return symbols.Add(lhs, false)
}
Ejemplo n.º 3
0
func rhsCase(l lexer.Lexer, tok string) (syms.SymbolID, error) {
	if tok == "" {
		return syms.ERROR, errors.New("empty rhs identifier")
	}
	symbols := l.GetSymbolSet()
	sid, err := symbols.GetByName(tok)
	if err == nil {
		return sid, nil
	}

	lt := len(tok)
	if isIdentName(tok) {
		return l.Ident(tok[1 : lt-1]), nil
	} else if isOperatorName(tok) {
		return l.Operator(tok[1 : lt-1]), nil
	}
	if tok == "" || !tokenRe.MatchString(tok) {
		return syms.ERROR, fmt.Errorf("%s is not a valid rhs identifier", tok)
	}
	sid, err = symbols.Add(tok, false)
	return sid, err
}
Ejemplo n.º 4
0
func NewGrammarBlock(l lexer.Lexer, ruleBlock string, funcMap map[string]UserFn) (Grammar, error) {
	// defer tlog.FuncLog(tlog.Func("NewGrammarBlock"))
	var rules []Rule
	arrowSep := "→"
	defineSep := "::="
	subruleSep := "|"
	ruleHandlerPrefix := "@"
	ruleList := strings.Split(ruleBlock, "\n")
	synthSymbols := make(map[string]bool)
	var lhsID syms.SymbolID
	var err error
	for lineno, r := range ruleList {
		r = strings.TrimSpace(r)
		if r == "" || strings.HasPrefix(r, "//") {
			continue
		}

		var rhs string
		if lhsID != syms.ERROR && strings.HasPrefix(r, subruleSep) {
			// new subrule, lhs stays the same
			rhs = r[len(subruleSep):]
		} else {
			// new rule
			idxArrow := strings.Index(r, arrowSep)
			idxDefine := strings.Index(r, defineSep)

			var lhs string
			if idxArrow < 0 && idxDefine < 0 {
				return Grammar{}, fmt.Errorf("rule on line %d has no '→' or '::=' symbol", lineno+1)
			} else if idxArrow >= 0 && (idxDefine < 0 || idxArrow < idxDefine) {
				lhs = r[:idxArrow]
				rhs = r[idxArrow+len(arrowSep):]
			} else {
				lhs = r[:idxDefine]
				rhs = r[idxDefine+len(defineSep):]
			}

			lhsTrim := strings.TrimSpace(lhs)
			if lhsTrim == "" || !identRe.MatchString(lhsTrim) {
				return Grammar{}, fmt.Errorf("line %d: '%s' is not a valid lhs identifier\n%s", lineno+1, lhs, r)
			}
			lhsID, err = lhsCase(l, lhsTrim)
			if err != nil {
				return Grammar{}, err
			}
		}

		var rhsa []syms.SymbolID
		var funcDecl string
		for _, tok := range strings.Fields(rhs) {
			if tok == subruleSep {
				if len(rhsa) == 0 {
					return Grammar{}, fmt.Errorf("line %d: empty partial rule\n%s", lineno+1, r)
				}
				rules = append(rules, Rule{lhsID, rhsa, funcMap[funcDecl]})
				rhsa = nil
				funcDecl = ""
			} else if strings.HasPrefix(tok, ruleHandlerPrefix) {
				if funcDecl != "" {
					return Grammar{}, fmt.Errorf("line %d: multiple function decls\n%s", lineno+1, r)
				}
				funcDecl = tok[len(ruleHandlerPrefix):]
			} else {
				sid, err := rhsCase(l, tok)
				if err != nil {
					return Grammar{}, fmt.Errorf("line %d: %s\n%s", lineno+1, err, r)
				}
				rhsa = append(rhsa, sid)
				if isSynthName(tok) {
					synthSymbols[tok] = true
				}
			}
		}
		if len(rhsa) == 0 {
			return Grammar{}, fmt.Errorf("line %d: empty rhs\n%s", lineno+1, r)
		}
		rules = append(rules, Rule{lhsID, rhsa, funcMap[funcDecl]})
	}
	newRules, err := makeSynthRules(l, synthSymbols, funcMap["synth"])
	if err != nil {
		return Grammar{}, nil
	}
	rules = append(rules, newRules...)

	return NewGrammar(l.GetSymbolSet(), rules)
}