Skip to content

Парсер языка 1С (bsl) посредством yacc грамматик. Парсер строит AST

License

Notifications You must be signed in to change notification settings

LazarenkoA/1c-language-parser

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Парсер языка 1С

Этот репозиторий содержит парсер для языка 1С, написанный на Go. Парсер использует yacc для эффективного синтаксического анализа и создает абстрактное синтаксическое дерево (AST) представления разобранного кода 1С.

Использование

go get github.com/LazarenkoA/1c-language-parser@master

package main

import (
	"fmt"

	"github.com/LazarenkoA/1c-language-parser/ast"
)

func main() {
	code := `Процедура ПодключитьВнешнююОбработку() 
                Если в = 1 И а = 1 или у = 3 Тогда

                КонецЕсли
            КонецПроцедуры`

	a := ast.NewAST(code)
	if err := a.Parse(); err == nil {
		jdata, _ := a.JSON()
		fmt.Println(string(jdata))
	}
}

Примеры использования

Примеры AST

Вот несколько примеров, демонстрирующих возможности парсера языка 1С:

Процедура Пример()
	Сообщить("Привет, мир!");
КонецПроцедуры

AST:

main.ModuleStatement{
  Name: "",
  Body: []main.Statement{
    main.FunctionOrProcedure{
      Type: 1,
      Name: "Пример",
      Body: []main.Statement{
        main.MethodStatement{
          Name:  "Сообщить",
          Param: []main.Statement{
            "Привет, мир!",
          },
        },
      },
      Export:            false,
      Params:            []main.ParamStatement{},
      Directive:         "",
      ExplicitVariables: map[string]main.VarStatement{},
    },
  },
}
Если a = b и c = 8 или истина Тогда
	Сообщить("Условие выполнено");
ИначеЕсли ВтороеУсловие Тогда
	Сообщить("Второе условие выполнено");
Иначе
	Сообщить("Ни одно из условий не выполнено");
КонецЕсли

AST:

main.ModuleStatement{
  Name: "",
  Body: []main.Statement{
    main.FunctionOrProcedure{
      Type: 1,
      Name: "Пример",
      Body: []main.Statement{
        main.IfStatement{
          Expression: main.ExpStatement{
            Operation: 11,
            Left:      main.ExpStatement{
              Operation: 12,
              Left:      main.ExpStatement{
                Operation: 4,
                Left:      main.VarStatement{
                  Name:  "a",
                  unary: false,
                  not:   false,
                },
                Right: main.VarStatement{
                  Name:  "b",
                  unary: false,
                  not:   false,
                },
                unary: false,
                not:   false,
              },
              Right: main.ExpStatement{
                Operation: 4,
                Left:      main.VarStatement{
                  Name:  "c",
                  unary: false,
                  not:   false,
                },
                Right: 8.000000,
                unary: false,
                not:   false,
              },
              unary: false,
              not:   false,
            },
            Right: true,
            unary: false,
            not:   false,
          },
          TrueBlock: []main.Statement{
            main.MethodStatement{
              Name:  "Сообщить",
              Param: []main.Statement{
                "Условие выполнено",
              },
            },
          },
          IfElseBlock: []*main.IfStatement{
            &main.IfStatement{
              Expression: main.VarStatement{
                Name:  "ВтороеУсловие",
                unary: false,
                not:   false,
              },
              TrueBlock: []main.Statement{
                main.MethodStatement{
                  Name:  "Сообщить",
                  Param: []main.Statement{
                    "Второе условие выполнено",
                  },
                },
              },
              IfElseBlock: []*main.IfStatement{},
              ElseBlock:   []main.Statement{},
            },
          },
          ElseBlock: []main.Statement{
            main.MethodStatement{
              Name:  "Сообщить",
              Param: []main.Statement{
                "Ни одно из условий не выполнено",
              },
            },
          },
        },
      },
      Export:            false,
      Params:            []main.ParamStatement{},
      Directive:         "",
      ExplicitVariables: map[string]main.VarStatement{},
    },
  },
}

Более сложный пример (код случайный)
Процедура ОткрытьНавигационнуюСсылку(НавигационнаяСсылка, Знач Оповещение = Неопределено) Экспорт
	
	Контекст = Новый Структура;
	Контекст.Вставить("НавигационнаяСсылка", НавигационнаяСсылка);
	Контекст.Вставить("Оповещение", Оповещение);
	
	ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось перейти по ссылке ""%1"" по причине: 
			           |Неверно задана навигационная ссылка.'"),
			НавигационнаяСсылка);
	
	Если Не ОбщегоНазначенияСлужебныйКлиент.ЭтоДопустимаяСсылка(НавигационнаяСсылка) Тогда 
		ОбщегоНазначенияСлужебныйКлиент.ОткрытьНавигационнуюСсылкуОповеститьОбОшибке(ОписаниеОшибки, Контекст);
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначенияСлужебныйКлиент.ЭтоВебСсылка(НавигационнаяСсылка)
		Или ОбщегоНазначенияСлужебныйКлиент.ЭтоНавигационнаяСсылка(НавигационнаяСсылка) Тогда 
		
		Попытка
			а = а /0;
		Исключение
			ОбщегоНазначенияСлужебныйКлиент.ОткрытьНавигационнуюСсылкуОповеститьОбОшибке(ОписаниеОшибки, Контекст);
			Возврат;
		КонецПопытки;
		
		Если Оповещение <> Неопределено Тогда 
			ПриложениеЗапущено = Истина;
			ВыполнитьОбработкуОповещения(Оповещение, ПриложениеЗапущено);
		КонецЕсли;
		
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначенияСлужебныйКлиент.ЭтоСсылкаНаСправку(НавигационнаяСсылка) Тогда 
		ОткрытьСправку(НавигационнаяСсылка);
		Возврат;
	КонецЕсли;
КонецПроцедуры
получаем такое AST
main.ModuleStatement{
  Name: "",
  Body: []main.Statement{
    main.FunctionOrProcedure{
      Type: 1,
      Name: "ОткрытьНавигационнуюСсылку",
      Body: []main.Statement{
        main.ExpStatement{
          Operation: 4,
          Left:      main.VarStatement{
            Name:  "Контекст",
            unary: false,
            not:   false,
          },
          Right: main.NewObjectStatement{
            Constructor: "Структура",
            Param:       []main.Statement{},
          },
          unary: false,
          not:   false,
        },
        main.CallChainStatement{
          Unit: main.MethodStatement{
            Name:  "Вставить",
            Param: []main.Statement{
              "НавигационнаяСсылка",
              main.VarStatement{
                Name:  "НавигационнаяСсылка",
                unary: false,
                not:   false,
              },
            },
          },
          Call: main.VarStatement{
            Name:  "Контекст",
            unary: false,
            not:   false,
          },
        },
        main.CallChainStatement{
          Unit: main.MethodStatement{
            Name:  "Вставить",
            Param: []main.Statement{
              "Оповещение",
              main.VarStatement{
                Name:  "Оповещение",
                unary: false,
                not:   false,
              },
            },
          },
          Call: main.VarStatement{
            Name:  "Контекст",
            unary: false,
            not:   false,
          },
        },
        main.ExpStatement{
          Operation: 4,
          Left:      main.VarStatement{
            Name:  "ОписаниеОшибки",
            unary: false,
            not:   false,
          },
          Right: main.CallChainStatement{
            Unit: main.MethodStatement{
              Name:  "ПодставитьПараметрыВСтроку",
              Param: []main.Statement{
                main.MethodStatement{
                  Name:  "НСтр",
                  Param: []main.Statement{
                    "ru = 'Не удалось перейти по ссылке \"\"%1\"\" по причине: \n\t\t\t           |Неверно задана навигационная ссылка.'",
                  },
                },
                main.VarStatement{
                  Name:  "НавигационнаяСсылка",

                  unary: false,
                  not:   false,
                },
              },
            },
            Call: main.VarStatement{
              Name:  "СтроковыеФункцииКлиентСервер",
              unary: false,
              not:   false,
            },
          },
          unary: false,
          not:   false,
        },
        main.IfStatement{
          Expression: main.CallChainStatement{
            Unit: main.MethodStatement{
              Name:  "ЭтоДопустимаяСсылка",
              Param: []main.Statement{
                main.VarStatement{
                  Name:  "НавигационнаяСсылка",
                  unary: false,
                  not:   false,
                },
              },
            },
            Call: main.VarStatement{
              Name:  "ОбщегоНазначенияСлужебныйКлиент",
              unary: false,
              not:   false,
            },
          },
          TrueBlock: []main.Statement{
            main.CallChainStatement{
              Unit: main.MethodStatement{
                Name:  "ОткрытьНавигационнуюСсылкуОповеститьОбОшибке",
                Param: []main.Statement{
                  main.VarStatement{
                    Name:  "ОписаниеОшибки",
                    unary: false,
                    not:   false,
                  },
                  main.VarStatement{
                    Name:  "Контекст",
                    unary: false,
                    not:   false,
                  },
                },
              },
              Call: main.VarStatement{
                Name:  "ОбщегоНазначенияСлужебныйКлиент",
                unary: false,
                not:   false,
              },
            },
            main.ReturnStatement{
              Param: nil,
            },
          },
          IfElseBlock: []*main.IfStatement{},
          ElseBlock:   []main.Statement{},
        },
        main.IfStatement{
          Expression: main.ExpStatement{
            Operation: 11,
            Left:      main.CallChainStatement{
              Unit: main.MethodStatement{
                Name:  "ЭтоВебСсылка",
                Param: []main.Statement{
                  main.VarStatement{
                    Name:  "НавигационнаяСсылка",
                    unary: false,
                    not:   false,
                  },
                },
              },
              Call: main.VarStatement{
                Name:  "ОбщегоНазначенияСлужебныйКлиент",
                unary: false,
                not:   false,
              },
            },
            Right: main.CallChainStatement{
              Unit: main.MethodStatement{
                Name:  "ЭтоНавигационнаяСсылка",
                Param: []main.Statement{
                  main.VarStatement{
                    Name:  "НавигационнаяСсылка",
                    unary: false,
                    not:   false,
                  },
                },
              },
              Call: main.VarStatement{
                Name:  "ОбщегоНазначенияСлужебныйКлиент",
                unary: false,
                not:   false,
              },
            },
            unary: false,
            not:   false,
          },
          TrueBlock: []main.Statement{
            main.TryStatement{
              Body: []main.Statement{
                main.ExpStatement{
                  Operation: 4,
                  Left:      main.VarStatement{
                    Name:  "а",
                    unary: false,
                    not:   false,
                  },
                  Right: main.ExpStatement{
                    Operation: 3,
                    Left:      main.VarStatement{
                      Name:  "а",
                      unary: false,
                      not:   false,
                    },
                    Right: 0.000000,
                    unary: false,
                    not:   false,
                  },
                  unary: false,
                  not:   false,
                },
              },
              Catch: []main.Statement{
                main.CallChainStatement{
                  Unit: main.MethodStatement{
                    Name:  "ОткрытьНавигационнуюСсылкуОповеститьОбОшибке",
                    Param: []main.Statement{
                      main.VarStatement{
                        Name:  "ОписаниеОшибки",
                        unary: false,
                        not:   false,
                      },
                      main.VarStatement{
                        Name:  "Контекст",
                        unary: false,
                        not:   false,
                      },
                    },
                  },
                  Call: main.VarStatement{
                    Name:  "ОбщегоНазначенияСлужебныйКлиент",
                    unary: false,
                    not:   false,
                  },
                },
                main.ReturnStatement{
                  Param: nil,
                },
              },
            },
            main.IfStatement{
              Expression: main.ExpStatement{
                Operation: 7,
                Left:      main.VarStatement{
                  Name:  "Оповещение",
                  unary: false,
                  not:   false,
                },
                Right: nil,
                unary: false,
                not:   false,
              },
              TrueBlock: []main.Statement{
                main.ExpStatement{
                  Operation: 4,
                  Left:      main.VarStatement{
                    Name:  "ПриложениеЗапущено",
                    unary: false,
                    not:   false,
                  },
                  Right: true,
                  unary: false,
                  not:   false,
                },
                main.MethodStatement{
                  Name:  "ВыполнитьОбработкуОповещения",
                  Param: []main.Statement{
                    main.VarStatement{
                      Name:  "Оповещение",
                      unary: false,
                      not:   false,
                    },
                    main.VarStatement{
                      Name:  "ПриложениеЗапущено",
                      unary: false,
                      not:   false,
                    },
                  },
                },
              },
              IfElseBlock: []*main.IfStatement{},
              ElseBlock:   []main.Statement{},
            },
            main.ReturnStatement{
              Param: nil,
            },
          },
          IfElseBlock: []*main.IfStatement{},
          ElseBlock:   []main.Statement{},
        },
        main.IfStatement{
          Expression: main.CallChainStatement{
            Unit: main.MethodStatement{
              Name:  "ЭтоСсылкаНаСправку",
              Param: []main.Statement{
                main.VarStatement{
                  Name:  "НавигационнаяСсылка",
                  unary: false,
                  not:   false,
                },
              },
            },
            Call: main.VarStatement{
              Name:  "ОбщегоНазначенияСлужебныйКлиент",
              unary: false,
              not:   false,
            },
          },
          TrueBlock: []main.Statement{
            main.MethodStatement{
              Name:  "ОткрытьСправку",
              Param: []main.Statement{
                main.VarStatement{
                  Name:  "НавигационнаяСсылка",
                  unary: false,
                  not:   false,
                },
              },
            },
            main.ReturnStatement{
              Param: nil,
            },
          },
          IfElseBlock: []*main.IfStatement{},
          ElseBlock:   []main.Statement{},
        },
      },
      Export: true,
      Params: []main.ParamStatement{
        main.ParamStatement{
          Name:    "НавигационнаяСсылка",
          IsValue: false,
          Default: nil,
        },
        main.ParamStatement{
          Name:    "Оповещение",
          IsValue: true,
          Default: main.UndefinedStatement{},
        },
      },
      Directive:         "",
      ExplicitVariables: map[string]main.VarStatement{},
    },
  },
}

Если у вас возникнут проблемы или у вас есть предложения по улучшению, не стесняйтесь создать issue. Также приветствуются ваши вклады!

About

Парсер языка 1С (bsl) посредством yacc грамматик. Парсер строит AST

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published