I'm working with Javacc to build a parser for a Pascal subset.
This is my code:
PARSER_BEGIN(Pascal)
import java.io.*;
public class Pascal {
public static void main(String args[]) throws ParseException,IOException {
Pascal parser = new Pascal(new FileInputStream(args[0]));
parser.Programa();
}
}
PARSER_END(Pascal)
SKIP :
{
" "
| "\t"
| "\n"
| "\r"
}
TOKEN :
{
<PROGRAM: "program">
| <INTEIRO: "integer">
| <REAL: "real">
| <VAR: "var">
| <OF: "of">
| <FUNCTION: "function">
| <PROCEDURE: "procedure">
| <LBRACE:"(">
| <RBRACE: ")">
| <SEMI: ";">
| <PTS: ":">
| <BEGIN: "begin">
| <END: "end">
| <ATRIB: ":=">
| <ARRAY: "array">
| <LBRACKETS: "[">
| <RBRACKETS: "]">
| <IF: "if">
| <THEN: "then">
| <ELSE: "else">
| <NOT: "not">
| <PLUS: "+">
| <MINUS: "-">
| <WHILE: "while">
| <DO: "do">
}
TOKEN :
{
<OPERADOR_MULTIPLICATIVO: ("*"|"/"|"div"|"mod"|"and")>
|
<OPERADOR_ADITIVO: ("+"| "-" | "or")>
|
<OPERADOR_RELACIONAL: ("=" | "<>" | "<" | "<=" | ">=" | ">")>
|
<ID: ["a"-"z","A"-"Z"] ( ["a"-"z","A"-"Z","0"-"9"])*>
|
<DIGT: ["0"-"9"] (["0"-"9"])*>
}
void Programa () :
{}
{ <PROGRAM> <ID> <LBRACE> Lista_de_identificadores() <RBRACE> <SEMI>
Declaracoes()
Declara_subprogram()
Enunciado_composto()
<EOF>
}
// lista_de_identificadores
void Lista_de_identificadores():
{}
{
<ID> Lista2()
}
void Lista2():
{}
{
("," <ID> Lista2())?
}
//declarações
void Declaracoes():
{}
{
(<VAR> Lista_de_identificadores() <PTS> Tipo() <SEMI>)*
}
// tipo
void Tipo():
{}
{
(Tipo_padrao() | <ARRAY> <LBRACKETS> <DIGT> <RBRACKETS> <OF> Tipo_padrao())
}
//tipo_padrao
void Tipo_padrao():
{}
{
(<INTEIRO> | <REAL>)
}
//declarações_de_subprogramas
void Declara_subprogram():
{}
{
(Subprogram() <SEMI>)*
}
//declaração_de_subprograma
void Subprogram():
{}
{
Cabecalho_subprogram()
Declaracoes()
Enunciado_composto()
}
//cabeçalho_de_subprograma
void Cabecalho_subprogram():
{}
{
(<FUNCTION> <ID> Argumentos() <PTS> Tipo_padrao() <SEMI>) | (<PROCEDURE> <ID> Argumentos())
}
//argumentos
void Argumentos():
{}
{
(<LBRACE> Lista_parametros() <RBRACE>)?
}
//lista_de_parâmetros
void Lista_parametros():
{}
{
Lista_de_identificadores() <PTS> Tipo() Lista_parametros2()
}
void Lista_parametros2():
{}
{
(<SEMI> Lista_de_identificadores() <PTS> Tipo() Lista_parametros2())?
}
//enunciado_composto
void Enunciado_composto():
{}
{
<BEGIN> Enunciados_opcionais() <END>
}
//enunciados_opcionais
void Enunciados_opcionais():
{}
{
(Lista_enunciados())?
}
//lista_de_enunciados
void Lista_enunciados():
{}
{
Enunciado() (<SEMI> Enunciado())*
}
void Enunciado():
{}
{
LOOKAHEAD(5)(Variavel() <ATRIB> Expressao()) | (Chamada_procedimento()) | (Enunciado_composto()) | (<IF> Expressao() <THEN> Enunciado() <ELSE> Enunciado()) | (<WHILE> Expressao() <DO> Enunciado())
}
void Variavel():
{}
{
LOOKAHEAD(2)(<ID>) | (<ID> <LBRACKETS> Expressao() <RBRACKETS>)
}
void Chamada_procedimento():
{}
{
LOOKAHEAD(2)(<ID>) | (<ID> <LBRACE> Lista_expressoes() <RBRACE>)
}
void Lista_expressoes():
{}
{
Expressao() Lista_expressoes2()
}
void Lista_expressoes2():
{}
{
("," Expressao() Lista_expressoes2())?
}
void Expressao():
{}
{
LOOKAHEAD(2)Expressao_simples() | Expressao_simples() <OPERADOR_RELACIONAL> Expressao_simples()
}
void Expressao_simples():
{}
{
LOOKAHEAD(3)(Termo() Expressao_simples2()) | (Sinal() Termo() Expressao_simples2())
}
void Expressao_simples2():
{}
{
(<OPERADOR_ADITIVO> Termo() Expressao_simples2())?
}
void Termo():
{}
{
Fator() Termo2()
}
void Termo2():
{}
{
(<OPERADOR_MULTIPLICATIVO> Fator() Termo2())?
}
void Fator():
{}
{
LOOKAHEAD(2)(<ID>) | (<ID> <LBRACE> Lista_expressoes() <RBRACE>) | (<DIGT>) | (<LBRACE> Expressao() <RBRACE>) | (<NOT> Fator())
}
void Sinal():
{}
{
(<PLUS> | <MINUS>)
}
And this is the input program:
program exemplo (input, output, test);
var x, y: integer;
function mdc (a, b: integer): integer;
begin
if b = 0 then mdc := a
else mdc := mdc (b, a mod b)
end;
begin
read(x, y);
write(mdc(x,y));
end;
Javacc returns this:
Exception in thread "main" ParseException: Encountered " <OPERADOR_RELACIONAL> "= "" at line 5, column 14.
Was expecting one of:
"then" ...
<OPERADOR_MULTIPLICATIVO> ...
<OPERADOR_ADITIVO> ...
<OPERADOR_MULTIPLICATIVO> ...
<OPERADOR_ADITIVO> ...
<OPERADOR_ADITIVO> ...
<OPERADOR_MULTIPLICATIVO> ...
<OPERADOR_ADITIVO> ...
at Pascal.generateParseException(Pascal.java:984)
at Pascal.jj_consume_token(Pascal.java:865)
at Pascal.Enunciado(Pascal.java:270)
at Pascal.Lista_enunciados(Pascal.java:235)
at Pascal.Enunciados_opcionais(Pascal.java:223)
at Pascal.Enunciado_composto(Pascal.java:211)
at Pascal.Subprogram(Pascal.java:137)
at Pascal.Declara_subprogram(Pascal.java:127)
at Pascal.Programa(Pascal.java:20)
at Pascal.main(Pascal.java:9)
The problem is, I can't understand why Javacc is expecting those arguments and calls the "=" wrong at the positiong he is. The part from the work on this especific context is this one (almost the complete code):
void Enunciado():
{}
{
LOOKAHEAD(5)(Variavel() <ATRIB> Expressao()) | (Chamada_procedimento()) | (Enunciado_composto()) | (<IF> Expressao() <THEN> Enunciado() <ELSE> Enunciado()) | (<WHILE> Expressao() <DO> Enunciado())
}
void Variavel():
{}
{
LOOKAHEAD(2)(<ID>) | (<ID> <LBRACKETS> Expressao() <RBRACKETS>)
}
void Chamada_procedimento():
{}
{
LOOKAHEAD(2)(<ID>) | (<ID> <LBRACE> Lista_expressoes() <RBRACE>)
}
void Lista_expressoes():
{}
{
Expressao() Lista_expressoes2()
}
void Lista_expressoes2():
{}
{
("," Expressao() Lista_expressoes2())?
}
void Expressao():
{}
{
LOOKAHEAD(2)Expressao_simples() | Expressao_simples() <OPERADOR_RELACIONAL> Expressao_simples()
}
void Expressao_simples():
{}
{
LOOKAHEAD(3)(Termo() Expressao_simples2()) | (Sinal() Termo() Expressao_simples2())
}
void Expressao_simples2():
{}
{
(<OPERADOR_ADITIVO> Termo() Expressao_simples2())?
}
void Termo():
{}
{
Fator() Termo2()
}
void Termo2():
{}
{
(<OPERADOR_MULTIPLICATIVO> Fator() Termo2())?
}
void Fator():
{}
{
LOOKAHEAD(2)(<ID>) | (<ID> <LBRACE> Lista_expressoes() <RBRACE>) | (<DIGT>) | (<LBRACE> Expressao() <RBRACE>) | (<NOT> Fator())
}
Someone can figure out where's the error? I've tried a lot of things but this right now looks good for me (and it's in fact not).
Thanks.
EDIT: The functions with the same name, but with the number 2 on the final, are made to eliminate the left recursion.
The problem is that you are using LOOKAHEAD in a way that just won't work. For example you have
LOOKAHEAD(2)Expressao_simples()
| Expressao_simples() <OPERADOR_RELACIONAL> Expressao_simples()
SO this says that if the next two tokens of input are consistent with an Expressao_simples take the first alternative, otherwise take the second alternative. Clearly in any situation where the second alternative might succeed, the next two tokens will be consistent with the first alternative too, so the first will be chosen.
Instead you can delay the choice until later
Expressao_simples()
(
<OPERADOR_RELACIONAL> Expressao_simples()
)?
Compare this code to the diagram in the Pascal Report (revised).
I don't have this particular parser/generator available to test,
but it seems strange that the parser seems to be regarding '= '
as a single token. I would investigate that first.
If that doesn't reveal the problem, then the next thing to investigate
is your definition of Expressao_simples.
I'm afraid that the easiest way to investigate a problem like this is a bit
painful - to temporarily strip back the grammar to the simplest possible case, see
if the parser accepts that and, if it does, expand the grammar and re-test
until you identify the problem.
In other words, start by defining PROGRAM as
PROGRAM : "a" "=" "b"
If the parser accepts that, try
PROGRAM : IDENTIFIER "=" IDENTIFIER
then
PROGRAM : IDENTIFIER RELATIONALOPERATOR IDENTIFIER
then
PROGRAM : SIMPLEEXPRESSION RELATIONALOPERATOR SIMPLEEXPRESSION
etc. Eventually, you should find the construct which is causing the problem.
I'd say "good luck!", but you don't really need it, just a lot of patience
and simple test-cases.
Related
I am writing a lexical analyzer using JFlex. When the word co is matched, we have to ignore what comes after until the end of the line (because it's a comment). For the moment, I have a boolean variable that changes to true whenever this word is matched and if an identifier or an operator is matched after co until the end of the line, I simply ignore it because I have an if condition in my Identifier and Operator token identification.
I am wondering if there is better way to do this and get rid of this if statement that appears everywhere?
Here is the code:
%% // Options of the scanner
%class Lexer
%unicode
%line
%column
%standalone
%{
private boolean isCommentOpen = false;
private void toggleIsCommentOpen() {
this.isCommentOpen = ! this.isCommentOpen;
}
private boolean getIsCommentOpen() {
return this.isCommentOpen;
}
%}
Operators = [\+\-]
Identifier = [A-Z]*
EndOfLine = \r|\n|\r\n
%%
{Operators} {
if (! getIsBlockCommentOpen() && ! getIsCommentOpen()) {
// Do Code
}
}
{Identifier} {
if (! getIsBlockCommentOpen() && ! getIsCommentOpen()) {
// Do Code
}
}
"co" {
toggleIsCommentOpen();
}
. {}
{EndOfLine} {
if (getIsCommentOpen()) {
toggleIsCommentOpen();
}
}
One way to do this is to use states in JFlex. We say that every time the word co is matched, we enter in a state named COMMENT_STATE and we do nothing until the end of the line. After the end of the line, we exit the COMMENT_STATE state. So here is the code:
%% // Options of the scanner
%class Lexer
%unicode
%line
%column
%standalone
Operators = [\+\-]
Identifier = [A-Z]*
EndOfLine = \r|\n|\r\n
%xstate YYINITIAL, COMMENT_STATE
%%
<YYINITIAL> {
"co" {yybegin(COMMENT_STATE);}
}
<COMMENT_STATE> {
{EndOfLine} {yybegin(YYINITIAL);}
. {}
}
{Operators} {// Do Code}
{Identifier} {// Do Code}
. {}
{EndOfLine} {}
With this new approach, the lexer is more simpler and it's also more readable.
I developed a Custom Language plugin based on this this tutorial.
My plugin parses key/value language files with format like below. Values can contain some HTML tags like <br>, <i>, <b>, <span> and \n. So I want to highlight these tags as separate PSI elements inside green PSI elements (values) (see pic). How can I overwrite my rules to get this?
#Section header
KEY1 = First<br>Value
KEY2 = Second\nValue
Bnf rules I use
lngFile ::= item_*
private item_ ::= (property|header|COMMENT|CRLF)
property ::= (KEY? SEPARATOR VALUE?) | KEY {
mixin="someClass"
implements="someClass"
methods=[getKey getValue getName setName getNameIdentifier getPresentation]
}
header ::= HEADER {
mixin="someClass"
implements="someClass"
methods=[getName setName getNameIdentifier getPresentation]
}
Flex
%%
%class LngLexer
%implements FlexLexer
%unicode
%function advance
%type IElementType
%eof{ return;
%eof}
CRLF=\R
WHITE_SPACE=[\ \n\t\f]
FIRST_VALUE_CHARACTER=[^ \n\f\\] | "\\"{CRLF} | "\\".
VALUE_CHARACTER=[^\n\f\\] | "\\"{CRLF} | "\\".
END_OF_LINE_COMMENT=("//")[^\r\n]*
HEADER=("#")[^\r\n]*
SEPARATOR=[:=]
KEY_CHARACTER=[^:=\ \n\t\f\\] | "\\ "
%state WAITING_VALUE
%%
<YYINITIAL> {END_OF_LINE_COMMENT} { yybegin(YYINITIAL); return LngTypes.COMMENT; }
<YYINITIAL> {HEADER} { yybegin(YYINITIAL); return LngTypes.HEADER; }
<YYINITIAL> {KEY_CHARACTER}+ { yybegin(YYINITIAL); return LngTypes.KEY; }
<YYINITIAL> {SEPARATOR} { yybegin(WAITING_VALUE); return LngTypes.SEPARATOR; }
<WAITING_VALUE> {CRLF}({CRLF}|{WHITE_SPACE})+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }
<WAITING_VALUE> {WHITE_SPACE}+ { yybegin(WAITING_VALUE); return TokenType.WHITE_SPACE; }
<WAITING_VALUE> {FIRST_VALUE_CHARACTER}{VALUE_CHARACTER}* { yybegin(YYINITIAL); return LngTypes.VALUE; }
({CRLF}|{WHITE_SPACE})+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }
[^] { return TokenType.BAD_CHARACTER; }
I started very recently to use bison for writing small compiler exercises. I am having some issues with white spaces ans comments. I was trying to debug the problem and I arrived to this source that looks like what I am looking for. I tried to chnage and erase some characters as advised but didn't work.
Also during compilation I have the following error: re2c: error: line 2963, column 0: can only difference char sets.
Below the part of the code:
yy::conj_parser::symbol_type yy::yylex(lexcontext& ctx)
{
const char* anchor = ctx.cursor;
ctx.loc.step();
// Add a lambda function to avoid repetition
auto s = [&](auto func, auto&&... params) { ctx.loc.columns(ctx.cursor - anchor); return func(params..., ctx.loc); };
%{ /* Begin re2c lexer : Tokenization process starts */
re2c:yyfill:enable = 0;
re2c:define:YYCTYPE = "char";
re2c:define:YYCURSOR = "ctx.cursor";
"return" { return s(conj_parser::make_RETURN); }
"while" | "for" { return s(conj_parser::make_WHILE); }
"var" { return s(conj_parser::make_VAR); }
"if" { return s(conj_parser::make_IF); }
// Identifiers
[a-zA-Z_] [a-zA-Z_0-9]* { return s(conj_parser::make_IDENTIFIER, std::string(anchor, ctx.cursor)); }
// String and integers:
"\""" [^\"]* "\"" { return s(conj_parser::make_STRINGCONST, std::string(anchor+1, ctx.cursor-1)); }
[0-9]+ { return s(conj_parser::make_NUMCONST, std::stol(std::string(anchor, ctx.cursor))); }
// Whitespace and comments:
"\000" { return s(conj_parser::make_END); }
"\r\n" | [\r\n] { ctx.loc.lines(); return yylex(ctx); }
"//" [^\r\n]* { return yylex(ctx); }
[\t\v\b\f ] { ctx.loc.columns(); return yylex(ctx); }
Thank you very much for pointing in the right direction or shading some lights on why this error could be solved.
You really should mention which line is line 2963. Perhaps it is here, because there seems to be an extra quotation mark in that line.
"\""" [^\"]* "\""
^
I'm trying scanning and parsing the mini-C code with lex and yacc, and I got some troubles.
I set tokens in scanner.l File like below,
...
"const" return tconst
"int" return tint
[A-Za-z][A-Za-z0-9]* return tident
...
and I declare production rule in parser.y File
...
dcl_specification : dcl_specifiers { semantic(8); };
dcl_specifiers : dcl_specifier { semantic(9); }
| dcl_specifiers dcl_specifier { semantic(10); };
dcl_specifier : type_qualifier { semantic(11); }
| type_specifier { semantic(12); };
type_qualifier : tconst { semantic(13); };
type_specifier : tint { semantic(14); };
...
%%
...
void semantic(int n) {
printf("%d\n", n);
}
...
then, I want to parse the text const int max=100,
result is
13
11
9
8
syntax error
I expect 10 shows up because const int might be reduced by rule 10,
but I'm wrong.
why this happens and what should I do?
please let me know
I'm new in Grails and I'm creating my first app and I'm having a little trouble finding where things happen, so, I have an object "cicle" that has many "measurements" and gets created by the measurement controller each time I create a new "measurement" that a different machine, this happens for the same machine, some properties of cicle change, so, I execute a method in cicle called updateCalculations that needs the data of the newly created measurement.
So in the measurementController I´m trying to perform some operations using measurements from cycle but I get a null pointer exception, I guessed cicle wasn't created so I moved the operation to the method afterInsert in Measurement object a place I thougth was better for this method to be invoqued, but I'm getting the same problem there, I even think cicle is created buy measurements some how isn't initialized, I don't know really whats happening, so can you help me?
this is my code:
Measurement.groovy
class Measurement{
String machine
int time1
int time2
int time3
int cicleValue
static belongsTo = [cicle: Cicle]
static constraints = {
machine blank:false
time1 nullable:false
time1 min:0
time2 nullable:false
time2 min:0
time3 nullable:false
time3 min:0
cicleValue nullable:false
cicleValue min:0
}
def afterInsert(){
this.cicle.updateCalculations()
}
public void updateCicleValue(){
double avgTime = (time1 + time2 + time3)/3
cicleValue = 30 * 24 * 60 * 60 / avgTime
}
}
Cicle.groovy
class Cicle {
String machine
int cicleValue
static hasMany = [measurements:Measurement]
static constraints = {
machine blank:false
cicleValue nullable:false
}
public void updateCalculations(){
int sumCicles = 0
measurements.each{ measurement ->
sumCicles += measurement.cicleValue
}
cicleValue = sumCicles / measurements.size()
this.save(failOnError: true)
}
}
MeasurementController.groovy
#Transactional(readOnly = true)
class MeasurementController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def create() {
respond new Measurement(params)
}
#Transactional
def save(Measurement measurementInstance) {
if (measurementInstance == null) {
notFound()
return
}
measurementInstance.updateCicleValue()
Cicle cicle = Cicle.findByMachine(measurementInstance.machine)
if(cicle == null){
cicle = new Cicle(machine: measurementInstance.machine, cicleValue: measurementInstance.cicleValue)
cicle.save flush: true
}
measurementInstance.cicle = cicle
measurementInstance.validate()
if (measurementInstance.hasErrors()) {
respond measurementInstance.errors, view:'create'
return
}
measurementInstance.save flush:true
cicle.measurements << measurementInstance
cicle.save flush: true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'measurementInstance.label', default: 'Measurement'), measurementInstance.id])
redirect measurementInstance
}
'*' { respond measurementInstance, [status: CREATED] }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'measurementInstance.label', default: 'Measurement'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
Here is the stack-trace from the console:
|Loading Grails 2.3.7
|Configuring classpath
.
|Environment set to development
.................................
|Packaging Grails application
...........
|Compiling 1 source files
...............................
|Running Grails application
|Server running. Browse to http://localhost:8080/mock-app
....Error
|
2014-04-24 21:51:34,719 [http-bio-8080-exec-3] ERROR errors.GrailsExceptionResolver - NullPointerException occurred when processing request: [POST] /mock-app/measurement/save - parameters:
time3: 20
time2: 20
time1: 20
machine: 2-12
create: Crear
Cannot invoke method size() on null object. Stacktrace follows:
Message: Cannot invoke method size() on null object
Line | Method
->> 23 | updateCalculations in com.rpc.mock.app.Cicle
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 26 | afterInsert in com.rpc.mock.app.Measurement
| 153 | call . . . . . . . in org.grails.datastore.gorm.support.EventTriggerCaller$MethodCaller
| 96 | call in org.grails.datastore.gorm.support.EventTriggerCaller
| 47 | onApplicationEvent in org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
| 51 | $tt__save in com.rpc.mock.app.MeasurementController
| 200 | doFilter . . . . . in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 1145 | runWorker . . . . in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 744 | run . . . . . . . in java.lang.Thread
it stops in the afterUpdate method telling measurements its null
Any help would be great
Thanks
This is beacause you forgot to add measurementInstance to the cicle.measurements.
Have a try and add it when saving cicle instance here:
if(cicle == null){
cicle = new Cicle(machine: measurementInstance.machine, cicleValue: measurementInstance.cicleValue)
cicle.addToMeasurements(measurementInstance) //add to collection
cicle.save flush: true
}